<?php
// +----------------------------------------------------------------------
// | 任务数据统计 类型服务
// +----------------------------------------------------------------------
// | 主要服务于任务数据统计数据处理
// +----------------------------------------------------------------------
// | 错误编码头 247xxx
// +----------------------------------------------------------------------

namespace common\service;

use common\model\PlaylistItemVersionModel;
use common\model\ReviewRequestNodeModel;
use common\exception\LogicException;
use common\model\ProjectMemberModel;
use common\model\ReviewRequestModel;
use common\model\TaskWorkOrderModel;
use support\EntityTaskFilterParser;
use common\model\StepCategoryModel;
use common\model\ProjectModel;
use common\model\StatusModel;
use common\model\EntityModel;
use common\model\PlanModel;
use common\model\StepModel;
use common\model\TaskModel;
use common\model\UserModel;
use support\SingletonTrait;
use think\module\Module;
use Webman\Stomp\Client;
use support\ErrorCode;
use think\Exception;
use think\Cache;

class TaskStatisticsService
{
    use SingletonTrait;
    use EntityTaskFilterParser;

    // 项目统计工序id
    protected $statisticalStepIds = [];

    // 状态映射
    protected $statusMapping = [];

    /**
     * 状态映射颜色
     *
     * 1、没任务 白色 待分配
     * 2、未开始 灰色 未开始
     * 3、正常 蓝色（进行中、审核）
     * 4、完成 绿色
     * 5、预警 黄色 TODO 暂时无法统计
     * 6、逾期 红色
     *
     * @var array
     */
    protected $statusColorMapping = [
        'not_started' => 'gray',
        'ready_to_start' => 'gray',
        'inprogress' => 'blue',
        'submitted' => 'blue',
        'feedback' => 'blue',
        'wait_for_party_a_review' => 'blue',
        'final' => 'green',
        'ready_to_publish' => 'green',
    ];

    // 当前时间戳
    protected $nowCurrentTimestamp = 0;

    public function __construct()
    {
        $this->nowCurrentTimestamp = time();
    }

    /**
     * 获取当前项目统计工序配置
     * @param $projectId
     * @param $type
     * @return mixed
     */
    protected function getTemplateStatisticalStepConfig($projectId, $type)
    {
        // 获取当前项目模板id
        $projectModel = model(ProjectModel::class);
        $projectTemplateId = $projectModel->where(['id' => $projectId])->getField('project_template_id');

        if (empty($projectTemplateId)) {
            throw new LogicException("There is no project template for the current project.", ErrorCode::NO_TEMPLATE_CONFIG_FOR_CURRENT_PROJECT);
        }

        // 获取当前项目统计工序配置
        $templateService = TemplateService::getInstance();
        try {
            $statisticalStepData = $templateService->getConfigSetting(['id' => $projectTemplateId], 'statistical_step');
        } catch (\Throwable $e) {
            if ($e->getCode() === ErrorCode::PROJECT_TEMPLATE_NOT_FOUND) {
                //获取默认配置
                $statisticalStepData = OptionsService::getInstance()->getOptionsData("statistical_step");
                if (!empty($statisticalStepData[$type])) {
                    $statisticalStepData[$type] = json_decode($statisticalStepData[$type], true);
                }
            }
        }

        if (empty($statisticalStepData[$type])) {
            throw new LogicException("Task statistics operation does not exist.", ErrorCode::TASK_STATISTICS_OPERATION_NOT_EXIST);
        }

        $statisticalStepDataIds = array_column($statisticalStepData[$type], 'id');
        $this->statisticalStepIds = $statisticalStepDataIds;

        //为一级分类填补二级分类映射数据
        $stepCategoryModel = model(StepCategoryModel::class);
        $secondLevelStepCategoryData = $stepCategoryModel->field('id,name,code,parent_id')->where(['parent_id' => ["in", join(",", $statisticalStepDataIds)]])->select();
        $stepCategoryParentIdMapping = [];
        //建立映射
        foreach ($secondLevelStepCategoryData as $secondLevelStepCategoryItem) {
            $stepCategoryParentIdMapping[$secondLevelStepCategoryItem['parent_id']][] = $secondLevelStepCategoryItem["id"];
        }

        //添加相应的二级分类 ，建立二级与一级分类的映射
        foreach ($statisticalStepData[$type] as &$statisticalStepItem) {
            if (array_key_exists($statisticalStepItem['id'], $stepCategoryParentIdMapping)) {
                $statisticalStepItem["sub_category"] = $stepCategoryParentIdMapping[$statisticalStepItem['id']];
            }
        }


        return $statisticalStepData[$type];
    }

    /**
     * 获取任务状态映射
     */
    protected function getTaskStatusMapping()
    {
        /**
         * 默认状态配置
         *
         * 1、not_started 未开始
         * 2、inprogress 进行中
         * 3、feedback 反馈
         * 4、final 已完成
         * 5、ready_to_publish 待发布
         * 6、wait_for_party_a_review 待客户审核
         */
        $defaultStatusListConfig = OptionsService::getInstance()->getTaskStatusList();

        $this->statusMapping = array_column($defaultStatusListConfig, null, 'id');
    }

    /**
     * 获取指定实体所属工序分类二级工序分类
     * @param $entityModuleId
     * @return array
     */
    protected function getEntitySecondLevelStepCategory($entityModuleId)
    {
        $isFirstLevel = false;
        $stepCategoryModel = model(StepCategoryModel::class);
        $firstLevelStepCategoryId = $stepCategoryModel->where(['entity_id' => $entityModuleId, 'parent_id' => 0])->getField('id');

        if (in_array($firstLevelStepCategoryId, $this->statisticalStepIds)) {
            $isFirstLevel = true;
        }

        if (empty($firstLevelStepCategoryId)) {
            throw_strack_exception("Incorrect step configuration.", ErrorCode::INCORRECT_STEP_CONFIG);
        }

        $secondLevelStepCategoryData = $stepCategoryModel->field('id,code')->where(['parent_id' => $firstLevelStepCategoryId])->select();

        if (empty($secondLevelStepCategoryData)) {
            return [];
        }

        $secondLevelStepCategoryDataNeedIds = [];

        foreach ($secondLevelStepCategoryData as $secondLevelStepCategoryItem) {
            if (in_array($secondLevelStepCategoryItem['id'], $this->statisticalStepIds) || $isFirstLevel) {
                $secondLevelStepCategoryDataNeedIds[] = $secondLevelStepCategoryItem['id'];
            }
        }

        return $secondLevelStepCategoryDataNeedIds;
    }

    public function getEntityStepTaskStatus($secondLevelStepCategoryIds, $entityIds)
    {
        $taskModel = model(TaskModel::class);
        $taskData = $taskModel
            ->field("id,name,entity_id,step_category_id,plan_end_time as step_plan_end_time,end_time as step_end_time,is_assignee,JSON_UNQUOTE(JSON_EXTRACT(json, '$.task_status')) AS task_status")
            ->where([
                'entity_id' => ['in', join(',', $entityIds)],
                'step_type' => 'step',
                'step_category_id' => ['in', join(',', $secondLevelStepCategoryIds)],
            ])
            ->order('task.entity_id asc')
            ->select();

        if (empty($taskData)) {
            return [];
        }

        foreach ($taskData as &$taskItem) {
            if (!empty($this->statusMapping[$taskItem['task_status']])) {
                $taskItem['status'] = $this->statusMapping[$taskItem['task_status']];
            } else {
                $taskItem['status'] = [];
            }

            //筛选掉
        }

        return $taskData;
    }

    /**
     * 获取实体关联实体数据集合
     * @param $ids
     * @param $linkField
     * @return array
     */
    public function getEntityLinkEntityData($ids, $linkField)
    {
        $entityModel = model(EntityModel::class);

        $entityData = $entityModel->field("
            id,
            name,
            entity_id,
            entity_module_id,
            JSON_UNQUOTE(JSON_EXTRACT(json, '$.{$linkField}')) AS {$linkField}
        ")
            ->where([
                'id' => ['in', join(',', $ids)]
            ])
            ->select();

        $resData = [
            'link_map' => [],
            'entity_ids' => []
        ];

        if (!empty($entityData)) {
            foreach ($entityData as $entityItem) {
                if (!in_array($linkField, $resData['entity_ids'])) {
                    $resData['entity_ids'][] = $linkField;
                }
                $resData['link_map'][$entityItem['id']][] = $entityItem[$linkField];
            }
        }

        return $resData;
    }


    /**
     * 处理状态颜色
     * @param $code
     * @param $endPlanTime
     * @param $endTime
     * @param string $isAssignee
     * @return mixed|string
     */
    protected function handlingStatusColor($code, $endPlanTime, $endTime, $isAssignee = 'no')
    {

        if ($endTime != 0 && $endTime > $endPlanTime) { //逾期且完成过的任务
            return 'pink';
        }

        if ($this->statusColorMapping[$code] != 'green' && $isAssignee === 'yes' && $endPlanTime < $this->nowCurrentTimestamp) { //当前正在逾期的任务
            return 'red';
        }

        return $this->statusColorMapping[$code];
    }

    /**
     * 处理状态冲突
     * @param $oldColor
     * @param $newColor
     * @return string
     */
    protected function handlingColorConflicts($oldColor, $newColor)
    {

        if (empty($oldColor)) {
            $oldColor = 'white';
        }
        if (empty($newColor)) {
            $newColor = 'white';
        }
        // red>yellow>blue>gray>pink>green>white
        // 逾期>预警>进行中>未开始>逾期完成>完成>没有任务

        $color = ['white', 'green', 'pink', 'gray', 'blue', 'yellow', 'red'];
        $oldColorKey = array_search($oldColor, $color);
        $newColorKey = array_search($newColor, $color);
        if ($oldColorKey <= $newColorKey) {
            return $newColor;
        } else {
            return $oldColor;
        }
    }

    /**
     * 获取最后一道工序任务
     * @param $oldTask
     * @param $newTask
     * @return mixed
     */
    public function compareEndTask($oldTask, $newTask)
    {
        if ($oldTask['id'] > $newTask['id']) {
            return $oldTask;
        } else {
            return $newTask;
        }
    }

    /**
     * 时间比较 (如果为完成的时间显示为0,都完成了比较最晚的出来)
     * @param $oldTime
     * @param $newTime
     * @return int|mixed
     */
    public function compareTime($oldTime, $newTime)
    {
        if (empty($oldTime) || empty($newTime)) {
            return 0;
        }

        return max($oldTime, $newTime);
    }

    /**
     * 修正镜头任务工序数据
     * @param $shotTaskData
     * @param $shotStepCategoryTasks
     */
    protected function reviseShotTaskStepCategoryData(&$shotTaskData, $shotStepCategoryTasks)
    {
        $compareTasks = [];
        foreach ($shotStepCategoryTasks as $shotStepCategoryTask) {
            if (empty($compareTasks[$shotStepCategoryTask['entity_id']][$shotStepCategoryTask['step_category_id']])) {
                $compareTasks[$shotStepCategoryTask['entity_id']][$shotStepCategoryTask['step_category_id']] = [
                    'end_task' => $shotStepCategoryTask,
                    'step_end_time' => $shotStepCategoryTask['step_end_time'],
                    'step_plan_end_time' => $shotStepCategoryTask['step_plan_end_time'],
                    'color' => $this->handlingStatusColor($shotStepCategoryTask['status']['code'], $shotStepCategoryTask['step_plan_end_time'], $shotStepCategoryTask['step_end_time'], $shotStepCategoryTask['is_assignee'])
                ];
            } else {
                $localTask = $compareTasks[$shotStepCategoryTask['entity_id']][$shotStepCategoryTask['step_category_id']];
                $localColor = $this->handlingStatusColor($shotStepCategoryTask['status']['code'], $shotStepCategoryTask['step_plan_end_time'], $shotStepCategoryTask['step_end_time'], $shotStepCategoryTask['is_assignee']);
                $endTask = $this->compareEndTask($localTask['end_task'], $shotStepCategoryTask);
                $compareTasks[$shotStepCategoryTask['entity_id']][$shotStepCategoryTask['step_category_id']] = [
                    'end_task' => $endTask,
                    'step_end_time' => $endTask['step_end_time'],
                    'step_plan_end_time' => $endTask['step_plan_end_time'],
                    'color' => $this->handlingColorConflicts($localTask['color'], $localColor)
                ];
            }
        }
        foreach ($compareTasks as $compareTaskEntityId => $compareTaskStepCategoryIdItem) {
            foreach ($compareTaskStepCategoryIdItem as $compareTaskStepCategoryId => $item) {
                $shotTaskData[$compareTaskEntityId][$compareTaskStepCategoryId] = $item;
            }
        }
    }

    /**
     * 修正集数任务工序数据
     * @param $episodeTaskData
     * @param $episodeStepCategoryTasks
     */
    protected function reviseEpisodeTaskStepCategoryData(&$episodeTaskData, $episodeStepCategoryTasks)
    {
        foreach ($episodeStepCategoryTasks as $episodeStepCategoryTask) {
            if (empty($episodeTaskData[$episodeStepCategoryTask['entity_id']][$episodeStepCategoryTask['step_category_id']])) {
                $episodeTaskData[$episodeStepCategoryTask['entity_id']][$episodeStepCategoryTask['step_category_id']] = [
                    'end_task' => $episodeStepCategoryTask,
                    'step_end_time' => $episodeStepCategoryTask['step_end_time'],
                    'step_plan_end_time' => $episodeStepCategoryTask['step_plan_end_time'],
                    'color' => $this->handlingStatusColor($episodeStepCategoryTask['status']['code'], $episodeStepCategoryTask['step_plan_end_time'], $episodeStepCategoryTask['step_end_time'], $episodeStepCategoryTask['is_assignee'])
                ];
            } else {
                $localTask = $episodeTaskData[$episodeStepCategoryTask['entity_id']][$episodeStepCategoryTask['step_category_id']];
                $localColor = $this->handlingStatusColor($episodeStepCategoryTask['status']['code'], $episodeStepCategoryTask['step_plan_end_time'], $episodeStepCategoryTask['step_end_time'], $episodeStepCategoryTask['is_assignee']);
                $endTask = $this->compareEndTask($localTask['end_task'], $episodeStepCategoryTask);
                $episodeTaskData[$episodeStepCategoryTask['entity_id']][$episodeStepCategoryTask['step_category_id']] = [
                    'end_task' => $endTask,
                    'step_end_time' => $endTask['step_end_time'],
                    'step_plan_end_time' => $endTask['step_plan_end_time'],
                    'color' => $this->handlingColorConflicts($localTask['color'], $localColor)
                ];
            }
        }
    }

    /**
     * 修正序列任务工序数据
     * @param $shotTaskData
     * @param $sequenceStepCategoryTasks
     * @param $shotSequenceMapping
     */
    protected function reviseSequenceTaskStepCategoryData(&$shotTaskData, $sequenceStepCategoryTasks, $shotSequenceMapping)
    {
//        $entityIds = array_column($sequenceStepCategoryTasks, 'entity_id');
//        //获取最后一道工序的任务
//        $stepTask = $this->getEndStepTask($entityIds);
//
//        foreach ($sequenceStepCategoryTasks as $sequenceStepCategoryTask) {
//            $color = $this->handlingStatusColor($sequenceStepCategoryTask['status']['code'], $sequenceStepCategoryTask['plan_end_time'], $sequenceStepCategoryTask['end_time'], $sequenceStepCategoryTask['is_assignee']);
//
//            if (!empty($shotSequenceMapping[$sequenceStepCategoryTask['entity_id']])) {
//                foreach ($shotSequenceMapping[$sequenceStepCategoryTask['entity_id']] as $shotId) {
//                    $shotTaskData[$shotId][$sequenceStepCategoryTask['step_category_id']] = [
//                        'entity_task' => [[
//                            'entity_id' => $sequenceStepCategoryTask['entity_id'],
//                            'task_id' => $sequenceStepCategoryTask['id'],
//                            'end_time' => $sequenceStepCategoryTask['end_time']
//                        ]],
//                        'end_time' => $stepTask[$sequenceStepCategoryTask['entity_id']]['end_time'],
//                        'plan_end_time' => $stepTask[$sequenceStepCategoryTask['entity_id']]['plan_end_time'],
//                        'color' => $color
//                    ];
//                }
//            }
//        }

        $compareTasks = [];
        foreach ($sequenceStepCategoryTasks as $sequenceStepCategoryTask) {
            if (!empty($shotSequenceMapping[$sequenceStepCategoryTask['entity_id']])) {
                foreach ($shotSequenceMapping[$sequenceStepCategoryTask['entity_id']] as $shotId) {
                    if (empty($compareTasks[$shotId][$sequenceStepCategoryTask['step_category_id']])) {
                        $compareTasks[$shotId][$sequenceStepCategoryTask['step_category_id']] = [
                            'end_task' => $sequenceStepCategoryTask,
                            'step_end_time' => $sequenceStepCategoryTask['step_end_time'],
                            'step_plan_end_time' => $sequenceStepCategoryTask['step_plan_end_time'],
                            'color' => $this->handlingStatusColor($sequenceStepCategoryTask['status']['code'], $sequenceStepCategoryTask['step_plan_end_time'], $sequenceStepCategoryTask['step_end_time'], $sequenceStepCategoryTask['is_assignee'])
                        ];
                    } else {
                        $localTask = $compareTasks[$shotId][$sequenceStepCategoryTask['step_category_id']];
                        $localColor = $this->handlingStatusColor($sequenceStepCategoryTask['status']['code'], $sequenceStepCategoryTask['step_plan_end_time'], $sequenceStepCategoryTask['step_end_time'], $sequenceStepCategoryTask['is_assignee']);
                        $endTask = $this->compareEndTask($localTask['end_task'], $sequenceStepCategoryTask);
                        $compareTasks[$shotId][$sequenceStepCategoryTask['step_category_id']] = [
                            'end_task' => $endTask,
                            'step_end_time' => $endTask['step_end_time'],
                            'step_plan_end_time' => $endTask['step_plan_end_time'],
                            'color' => $this->handlingColorConflicts($localTask['color'], $localColor)
                        ];
                    }
                }
            }
        }
        foreach ($compareTasks as $compareTaskEntityId => $compareTaskStepCategoryIdItem) {
            foreach ($compareTaskStepCategoryIdItem as $compareTaskStepCategoryId => $item) {
                $shotTaskData[$compareTaskEntityId][$compareTaskStepCategoryId] = $item;
            }
        }


    }

    /**
     * 修正故事板
     * @param $shotTaskData
     * @param $storyboardStepCategoryTasks
     * @param $shotStoryboardMapping
     */
    protected function reviseStoryboardTaskStepCategoryData(&$shotTaskData, $storyboardStepCategoryTasks, $shotStoryboardMapping)
    {
        $storyboardData = [];
        foreach ($storyboardStepCategoryTasks as $storyboardStepCategoryTask) {
            if (empty($storyboardData[$storyboardStepCategoryTask['entity_id']][$storyboardStepCategoryTask['step_category_id']])) {
                $storyboardData[$storyboardStepCategoryTask['entity_id']][$storyboardStepCategoryTask['step_category_id']] = [
                    'end_task' => $storyboardStepCategoryTask,
                    'step_end_time' => $storyboardStepCategoryTask['step_end_time'],
                    'step_plan_end_time' => $storyboardStepCategoryTask['step_plan_end_time'],
                    'color' => $this->handlingStatusColor($storyboardStepCategoryTask['status']['code'], $storyboardStepCategoryTask['step_plan_end_time'], $storyboardStepCategoryTask['step_end_time'], $storyboardStepCategoryTask['is_assignee'])
                ];
            } else {
                $localTask = $storyboardData[$storyboardStepCategoryTask['entity_id']][$storyboardStepCategoryTask['step_category_id']];
                $localColor = $this->handlingStatusColor($storyboardStepCategoryTask['status']['code'], $storyboardStepCategoryTask['step_plan_end_time'], $storyboardStepCategoryTask['step_end_time'], $storyboardStepCategoryTask['is_assignee']);
                $endTask = $this->compareEndTask($localTask['end_task'], $storyboardStepCategoryTask);
                $storyboardData[$storyboardStepCategoryTask['entity_id']][$storyboardStepCategoryTask['step_category_id']] = [
                    'end_task' => $endTask,
                    'step_end_time' => $endTask['step_end_time'],
                    'step_plan_end_time' => $endTask['step_plan_end_time'],
                    'color' => $this->handlingColorConflicts($localTask['color'], $localColor)
                ];
            }
        }


        // 回插镜头数据
        foreach ($shotStoryboardMapping as $shotId => $storyboardIds) {
            foreach ($storyboardIds as $storyboardId) {
                if (!empty($storyboardData[$storyboardId])) {
                    foreach ($storyboardData[$storyboardId] as $assetStepCategoryId => $config) {
                        if (!array_key_exists($shotId, $shotTaskData) || !array_key_exists($assetStepCategoryId, $shotTaskData[$shotId])) {
                            $shotTaskData[$shotId][$assetStepCategoryId]['color'] = $config['color'];
                            $shotTaskData[$shotId][$assetStepCategoryId]['step_end_time'] = $config['step_end_time'];
                            $shotTaskData[$shotId][$assetStepCategoryId]['step_plan_end_time'] = $config['step_plan_end_time'];
                        } else {
                            $shotTaskData[$shotId][$assetStepCategoryId]['color'] = $this->handlingColorConflicts($shotTaskData[$shotId][$assetStepCategoryId]['color'], $config['color']);
                            $shotTaskData[$shotId][$assetStepCategoryId]['step_end_time'] = $this->compareTime($shotTaskData[$shotId][$assetStepCategoryId][$assetStepCategoryId]['step_end_time'], $config['step_end_time']);
                            $shotTaskData[$shotId][$assetStepCategoryId]['step_plan_end_time'] = $this->compareTime($shotTaskData[$shotId][$assetStepCategoryId][$assetStepCategoryId]['step_plan_end_time'], $config['step_plan_end_time']);
                        }
//                        $shotTaskData[$shotId][$assetStepCategoryId]['entity_task'][] = $config['entity_task'];
                    }
                }
            }
        }
    }

    /**
     * 修正序列关联资产和关卡数据
     * @param $shotTaskData
     * @param $assetStepCategoryTasks
     * @param $shotSequenceMapping
     * @param $sequenceLinkMapping
     */
    protected function reviseSequenceLinkTaskStepCategoryData(&$shotTaskData, $assetStepCategoryTasks, $shotSequenceMapping, $sequenceLinkMapping)
    {
        $assetData = [];

        foreach ($assetStepCategoryTasks as $assetStepCategoryTask) {
            if (empty($assetData[$assetStepCategoryTask['entity_id']][$assetStepCategoryTask['step_category_id']])) {
                $assetData[$assetStepCategoryTask['entity_id']][$assetStepCategoryTask['step_category_id']] = [
                    'end_task' => $assetStepCategoryTask,
                    'step_end_time' => $assetStepCategoryTask['step_end_time'],
                    'step_plan_end_time' => $assetStepCategoryTask['step_plan_end_time'],
                    'color' => $this->handlingStatusColor($assetStepCategoryTask['status']['code'], $assetStepCategoryTask['step_plan_end_time'], $assetStepCategoryTask['step_end_time'], $assetStepCategoryTask['is_assignee'])
                ];
            } else {
                $localTask = $assetData[$assetStepCategoryTask['entity_id']][$assetStepCategoryTask['step_category_id']];
                $localColor = $this->handlingStatusColor($assetStepCategoryTask['status']['code'], $assetStepCategoryTask['step_plan_end_time'], $assetStepCategoryTask['step_end_time'], $assetStepCategoryTask['is_assignee']);
                $endTask = $this->compareEndTask($localTask['end_task'], $assetStepCategoryTask);
                $assetData[$assetStepCategoryTask['entity_id']][$assetStepCategoryTask['step_category_id']] = [
                    'end_task' => $endTask,
                    'step_end_time' => $endTask['step_end_time'],
                    'step_plan_end_time' => $endTask['step_plan_end_time'],
                    'color' => $this->handlingColorConflicts($localTask['color'], $localColor)
                ];
            }
        }

        $sequenceLinkData = [];
        foreach ($sequenceLinkMapping as $sequenceId => $sequenceLinkIds) {
            $sequenceLinkData[$sequenceId] = [];
            foreach ($sequenceLinkIds as $sequenceLinkId) {
                if (array_key_exists($sequenceLinkId, $assetData)) {
                    foreach ($assetData[$sequenceLinkId] as $assetStepCategoryId => $config) {
                        if (array_key_exists($assetStepCategoryId, $sequenceLinkData[$sequenceId])) {
                            $sequenceLinkData[$sequenceId][$assetStepCategoryId]['color'] = $this->handlingColorConflicts($sequenceLinkData[$sequenceId][$assetStepCategoryId]['color'], $config['color']);
                            $sequenceLinkData[$sequenceId][$assetStepCategoryId]['step_end_time'] = $this->compareTime($sequenceLinkData[$sequenceId][$assetStepCategoryId]['step_end_time'], $config['step_end_time']);
                            $sequenceLinkData[$sequenceId][$assetStepCategoryId]['step_plan_end_time'] = $this->compareTime($sequenceLinkData[$sequenceId][$assetStepCategoryId]['step_plan_end_time'], $config['step_plan_end_time']);
                        } else {
                            $sequenceLinkData[$sequenceId][$assetStepCategoryId]['color'] = $config['color'];
                            $sequenceLinkData[$sequenceId][$assetStepCategoryId]['step_end_time'] = $config['step_end_time'];
                            $sequenceLinkData[$sequenceId][$assetStepCategoryId]['step_plan_end_time'] = $config['step_plan_end_time'];
                        }
//                        $sequenceLinkData[$sequenceId][$assetStepCategoryId]['entity_task'][] = $config['entity_task'];
                    }
                }
            }
        }

        // 回插镜头数据
        foreach ($shotSequenceMapping as $sequenceId => $shotIds) {
            if (!empty($sequenceLinkData[$sequenceId])) {
                foreach ($shotIds as $shotId) {
                    foreach ($sequenceLinkData[$sequenceId] as $assetStepCategoryId => $config) {
                        $shotTaskData[$shotId][$assetStepCategoryId] = $config;
                    }
                }
            }
        }
    }

    /**
     * 修正序列关联概念数据
     * @param $shotTaskData
     * @param $designStepCategoryTasks
     * @param $shotSequenceMapping
     * @param $assetDesignDataMapping
     * @param $levelDesignDataMapping
     * @param $sequenceAssetMapping
     * @param $sequenceLevelMapping
     */
    protected function reviseDesignLinkTaskStepCategoryData(&$shotTaskData, $designStepCategoryTasks, $shotSequenceMapping, $assetDesignDataMapping, $levelDesignDataMapping, $sequenceAssetMapping, $sequenceLevelMapping)
    {
        $designData = [];

        foreach ($designStepCategoryTasks as $designStepCategoryTask) {
            if (empty($designData[$designStepCategoryTask['entity_id']][$designStepCategoryTask['step_category_id']])) {
                $designData[$designStepCategoryTask['entity_id']][$designStepCategoryTask['step_category_id']] = [
                    'end_task' => $designStepCategoryTask,
                    'step_end_time' => $designStepCategoryTask['step_end_time'],
                    'step_plan_end_time' => $designStepCategoryTask['step_plan_end_time'],
                    'color' => $this->handlingStatusColor($designStepCategoryTask['status']['code'], $designStepCategoryTask['step_plan_end_time'], $designStepCategoryTask['step_end_time'], $designStepCategoryTask['is_assignee'])
                ];
            } else {
                $localTask = $designData[$designStepCategoryTask['entity_id']][$designStepCategoryTask['step_category_id']];
                $localColor = $this->handlingStatusColor($designStepCategoryTask['status']['code'], $designStepCategoryTask['step_plan_end_time'], $designStepCategoryTask['step_end_time'], $designStepCategoryTask['is_assignee']);
                $endTask = $this->compareEndTask($localTask['end_task'], $designStepCategoryTask);
                $designData[$designStepCategoryTask['entity_id']][$designStepCategoryTask['step_category_id']] = [
                    'end_task' => $endTask,
                    'step_end_time' => $endTask['step_end_time'],
                    'step_plan_end_time' => $endTask['step_plan_end_time'],
                    'color' => $this->handlingColorConflicts($localTask['color'], $localColor)
                ];
            }
        }

        $assetDesignDict = [];
        foreach ($assetDesignDataMapping as $assetId => $designId) {
            if (!empty($designId[0]) && array_key_exists($designId[0], $designData)) {
                $assetDesignDict[$assetId] = $designData[$designId[0]];
            }
        }

        $levelDesignDict = [];
        foreach ($levelDesignDataMapping as $levelId => $designId) {
            if (!empty($designId[0]) && array_key_exists($designId[0], $designData)) {
                $levelDesignDict[$levelId] = $designData[$designId[0]];
            }
        }

        $sequenceLinkData = [];
        // 序列关联资产
        foreach ($sequenceAssetMapping as $sequenceId => $sequenceAssetIds) {
            $sequenceLinkData[$sequenceId] = [];
            foreach ($sequenceAssetIds as $sequenceAssetId) {
                if (!isset($assetDesignDict[$sequenceAssetId])) {
                    continue;
                }
                foreach ($assetDesignDict[$sequenceAssetId] as $assetStepCategoryId => $config) {
                    if (array_key_exists($assetStepCategoryId, $sequenceLinkData[$sequenceId])) {
                        $sequenceLinkData[$sequenceId][$assetStepCategoryId]['color'] = $this->handlingColorConflicts($sequenceLinkData[$sequenceId][$assetStepCategoryId]['color'], $config['color']);
                        $sequenceLinkData[$sequenceId][$assetStepCategoryId]['step_end_time'] = $this->compareTime($sequenceLinkData[$sequenceId][$assetStepCategoryId]['step_end_time'], $config['step_end_time']);
                        $sequenceLinkData[$sequenceId][$assetStepCategoryId]['step_plan_end_time'] = $this->compareTime($sequenceLinkData[$sequenceId][$assetStepCategoryId]['step_plan_end_time'], $config['step_plan_end_time']);
                    } else {
                        $sequenceLinkData[$sequenceId][$assetStepCategoryId]['color'] = $config['color'];
                        $sequenceLinkData[$sequenceId][$assetStepCategoryId]['step_end_time'] = $config['step_end_time'];
                        $sequenceLinkData[$sequenceId][$assetStepCategoryId]['step_plan_end_time'] = $config['step_plan_end_time'];
                    }
//                    $sequenceLinkData[$sequenceId][$assetStepCategoryId]['entity_task'][] = $config['entity_task'];
                }
            }
        }

        // 序列关联关卡
        foreach ($sequenceLevelMapping as $sequenceId => $sequenceLevelIds) {
            $sequenceLinkData[$sequenceId] = [];
            foreach ($sequenceLevelIds as $sequenceLevelId) {
                if (!isset($levelDesignDict[$sequenceLevelId])) {
                    continue;
                }
                foreach ($levelDesignDict[$sequenceLevelId] as $assetStepCategoryId => $config) {
                    if (array_key_exists($assetStepCategoryId, $sequenceLinkData[$sequenceId])) {
                        $sequenceLinkData[$sequenceId][$assetStepCategoryId]['color'] = $this->handlingColorConflicts($sequenceLinkData[$sequenceId][$assetStepCategoryId]['color'], $config['color']);
                        $sequenceLinkData[$sequenceId][$assetStepCategoryId]['step_end_time'] = $this->compareTime($sequenceLinkData[$sequenceId][$assetStepCategoryId]['step_end_time'], $config['step_end_time']);
                        $sequenceLinkData[$sequenceId][$assetStepCategoryId]['step_plan_end_time'] = $this->compareTime($sequenceLinkData[$sequenceId][$assetStepCategoryId]['step_plan_end_time'], $config['step_plan_end_time']);
                    } else {
                        $sequenceLinkData[$sequenceId][$assetStepCategoryId]['color'] = $config['color'];
                        $sequenceLinkData[$sequenceId][$assetStepCategoryId]['step_end_time'] = $config['step_end_time'];
                        $sequenceLinkData[$sequenceId][$assetStepCategoryId]['step_plan_end_time'] = $config['step_plan_end_time'];
                    }
//                    $sequenceLinkData[$sequenceId][$assetStepCategoryId]['entity_task'][] = $config['entity_task'];
                }
            }
        }

        foreach ($shotSequenceMapping as $sequenceId => $shotIds) {
            if (!empty($sequenceLinkData[$sequenceId])) {
                foreach ($shotIds as $shotId) {
                    foreach ($sequenceLinkData[$sequenceId] as $assetStepCategoryId => $config) {
                        $shotTaskData[$shotId][$assetStepCategoryId] = $config;
                    }
                }
            }
        }

    }

    /**
     * 得到资产概念所需的任务数据
     * @param $assetAndLevelTaskData
     * @param $assetDesignStepCategoryTasks
     * @param $assetDesignMapping
     */
    protected function reviseAssetDesignTaskStepCategoryData(&$assetAndLevelTaskData, $assetDesignStepCategoryTasks, $assetDesignMapping)
    {
        $assetData = [];
        foreach ($assetDesignStepCategoryTasks as $assetDesignStepCategoryTask) {
            if (empty($assetData[$assetDesignStepCategoryTask['entity_id']][$assetDesignStepCategoryTask['step_category_id']])) {
                $assetData[$assetDesignStepCategoryTask['entity_id']][$assetDesignStepCategoryTask['step_category_id']] = [
                    'end_task' => $assetDesignStepCategoryTask,
                    'step_end_time' => $assetDesignStepCategoryTask['step_end_time'],
                    'step_plan_end_time' => $assetDesignStepCategoryTask['step_plan_end_time'],
                    'color' => $this->handlingStatusColor($assetDesignStepCategoryTask['status']['code'], $assetDesignStepCategoryTask['step_plan_end_time'], $assetDesignStepCategoryTask['step_end_time'], $assetDesignStepCategoryTask['is_assignee'])
                ];
            } else {
                $localTask = $assetData[$assetDesignStepCategoryTask['entity_id']][$assetDesignStepCategoryTask['step_category_id']];
                $localColor = $this->handlingStatusColor($assetDesignStepCategoryTask['status']['code'], $assetDesignStepCategoryTask['step_plan_end_time'], $assetDesignStepCategoryTask['step_end_time'], $assetDesignStepCategoryTask['is_assignee']);
                $endTask = $this->compareEndTask($localTask['end_task'], $assetDesignStepCategoryTask);
                $assetData[$assetDesignStepCategoryTask['entity_id']][$assetDesignStepCategoryTask['step_category_id']] = [
                    'end_task' => $endTask,
                    'step_end_time' => $endTask['step_end_time'],
                    'step_plan_end_time' => $endTask['step_plan_end_time'],
                    'color' => $this->handlingColorConflicts($localTask['color'], $localColor)
                ];
            }
        }


        // 资产、关卡映射概念
        foreach ($assetDesignMapping as $assetId => $designId) {
            if (!empty($designId)) {
                if (array_key_exists($designId, $assetData)) {
                    foreach ($assetData[$designId] as $stepCategoryId => $assetDataItem) {
                        if (array_key_exists($assetId, $assetAndLevelTaskData)) {
                            if (array_key_exists($stepCategoryId, $assetAndLevelTaskData[$assetId])) {
                                $assetAndLevelTaskData[$assetId][$stepCategoryId]['color'] = $this->handlingColorConflicts($assetAndLevelTaskData[$assetId][$stepCategoryId], $assetDataItem['color']);
                                $assetAndLevelTaskData[$assetId][$stepCategoryId]['step_end_time'] = $this->compareTime($assetAndLevelTaskData[$assetId][$stepCategoryId]['step_end_time'], $assetDataItem['step_end_time']);
                                $assetAndLevelTaskData[$assetId][$stepCategoryId]['step_plan_end_time'] = $this->compareTime($assetAndLevelTaskData[$assetId][$stepCategoryId]['step_plan_end_time'], $assetDataItem['step_plan_end_time']);
                            } else {
                                $assetAndLevelTaskData[$assetId][$stepCategoryId]['step_end_time'] = $assetDataItem['step_end_time'];
                                $assetAndLevelTaskData[$assetId][$stepCategoryId]['step_plan_end_time'] = $assetDataItem['step_plan_end_time'];
                                $assetAndLevelTaskData[$assetId][$stepCategoryId]['color'] = $assetDataItem['color'];
                            }
//                            $assetAndLevelTaskData[$assetId][$stepCategoryId]['entity_task'][] = $assetDataItem['entity_task'];
                        } else {
                            $assetAndLevelTaskData[$assetId] = [];
                        }
                    }
                }
            }
        }

    }

    /**
     * 得到资产与关卡所需的任务数据
     * @param $assetAndLevelTaskData
     * @param $assetStepCategoryTasks
     */
    protected function reviseAssetTaskStepCategoryData(&$assetAndLevelTaskData, $assetStepCategoryTasks)
    {
        $compareTasks = [];
        foreach ($assetStepCategoryTasks as $assetStepCategoryTask) {
            if (empty($compareTasks[$assetStepCategoryTask['entity_id']][$assetStepCategoryTask['step_category_id']])) {
                $compareTasks[$assetStepCategoryTask['entity_id']][$assetStepCategoryTask['step_category_id']] = [
                    'end_task' => $assetStepCategoryTask,
                    'step_end_time' => $assetStepCategoryTask['step_end_time'],
                    'step_plan_end_time' => $assetStepCategoryTask['step_plan_end_time'],
                    'color' => $this->handlingStatusColor($assetStepCategoryTask['status']['code'], $assetStepCategoryTask['step_plan_end_time'], $assetStepCategoryTask['step_end_time'], $assetStepCategoryTask['is_assignee'])
                ];
            } else {
                $localTask = $compareTasks[$assetStepCategoryTask['entity_id']][$assetStepCategoryTask['step_category_id']];
                $localColor = $this->handlingStatusColor($assetStepCategoryTask['status']['code'], $assetStepCategoryTask['step_plan_end_time'], $assetStepCategoryTask['step_end_time'], $assetStepCategoryTask['is_assignee']);
                $endTask = $this->compareEndTask($localTask['end_task'], $assetStepCategoryTask);
                $compareTasks[$assetStepCategoryTask['entity_id']][$assetStepCategoryTask['step_category_id']] = [
                    'end_task' => $endTask,
                    'step_end_time' => $endTask['step_end_time'],
                    'step_plan_end_time' => $endTask['step_plan_end_time'],
                    'color' => $this->handlingColorConflicts($localTask['color'], $localColor)
                ];
            }
        }

        //            $assetAndLevelTaskData[$assetStepCategoryTask['entity_id']][$assetStepCategoryTask['step_category_id']] = [
//                'entity_task' => [[
//                    'entity_id' => $assetStepCategoryTask['entity_id'],
//                    'task_id' => $assetStepCategoryTask['id'],
//                    'end_time' => $assetStepCategoryTask['end_time']
//                ]],

//                'step_end_time' => $stepTask[$assetStepCategoryTask['entity_id']]['end_time'],
//                'step_plan_end_time' => $stepTask[$assetStepCategoryTask['entity_id']]['plan_end_time'],
//                'color' => $this->handlingStatusColor($assetStepCategoryTask['status']['code'], $assetStepCategoryTask['plan_end_time'], $assetStepCategoryTask['end_time'], $assetStepCategoryTask['is_assignee'])
//            ];

        foreach ($compareTasks as $compareTaskEntityId => $compareTaskStepCategoryIdItem) {
            foreach ($compareTaskStepCategoryIdItem as $compareTaskStepCategoryId => $item) {
                $assetAndLevelTaskData[$compareTaskEntityId][$compareTaskStepCategoryId] = $item;
            }
        }
    }


    /**
     * 通过集数数据获取序列id数据
     * @param $episodeId
     * @return array
     */
    protected function getProjectSequenceIdsByEpisodeId($episodeId)
    {
        $entityModel = model(EntityModel::class);
        // 查询属于这一集的所有序列id
        $sequenceData = $entityModel->field('id')
            ->where([
                'entity_module_id' => Module::$moduleDictData['module_index_by_code']['episode']['id'],
                'entity_id' => $episodeId
            ])
            ->select();

        return !empty($sequenceData) ? array_column($sequenceData, 'id') : [];
    }


    /**
     * 生成指定项目的任务分析数据缓存
     * @param $projectId
     */
    public function generateProjectEpisodeTaskStatisticsAction($projectId)
    {
        // 获取当前项目所有集数
        $entityModel = model(EntityModel::class);

        $episodeData = $entityModel->field('id')
            ->where([
                'project_id' => $projectId,
                'module_id' => Module::$moduleDictData['module_index_by_code']['episode']['id']
            ])
            ->select();


        foreach ($episodeData as $episodeItem) {
            $episodeId = $episodeItem['id'];

            // 生成镜头缓存
            $shotCache = $this->getProjectTaskAllLifeCycleStatisticsByShot([
                "project_id" => $projectId,
                "episode_id" => $episodeId
            ]);

            // 设置缓存
            $cacheShotPrefix = "task_all_life_statistics_shot_{$projectId}_{$episodeId}";
            Cache::set($cacheShotPrefix, $shotCache, 3600);

            // 生成资产缓存
            $assetCache = $this->getProjectTaskAllLifeCycleStatisticsByAsset([
                "project_id" => $projectId,
                "episode_id" => $episodeId
            ]);

            // 设置缓存
            $cacheAssetPrefix = "task_all_life_statistics_asset_{$projectId}_{$episodeId}";
            Cache::set($cacheAssetPrefix, $assetCache, 3600);
        }

        // 设置当前缓存标记
        $cachePrefix = "project_ep_all_life_statistics_{$projectId}";
        $value = 'complete_' . time();
        Cache::set($cachePrefix, $value, 1800);
    }

    /**
     * 获取当前全生命周期缓存状态
     * @param $projectId
     * @return array
     */
    public function getProjectEpisodeTaskStatisticsStatus($projectId)
    {
        list($status, $expireTime) = $this->checkProjectEpisodeTaskCycleStatisticsCache($projectId, true);
        $expireDate = '';
        $statusStr = 'no';
        if ($status) {
            $expireDate = get_format_date($expireTime, 1);
            $statusStr = 'yes';
        }

        return [
            'cache_complete' => $statusStr,
            'last_cache_date' => $expireDate,
        ];
    }

    /**
     * 刷新当前全生命周期缓存
     * @param $projectId
     * @return array
     */
    public function refreshProjectEpisodeTaskStatisticsCache($projectId)
    {
        $cachePrefix = "project_ep_all_life_statistics_{$projectId}";
        $cache = Cache::get($cachePrefix);
        if (!empty($cache)) {
            $array = explode('_', $cache);
            if (time() <= ((int)$array[1] + 120)) {
                // 刷新间隔为两分钟
                throw_strack_exception('Two minute refresh interval.', ErrorCode::TwoMinuteRefreshInterval);
            }
        }

        // 刷新缓存
        $this->generateProjectEpisodeTaskStatistics($projectId);

        return [];
    }


    /**
     * 生成指定项目的任务分析数据缓存
     * @param $projectId
     */
    protected function generateProjectEpisodeTaskStatistics($projectId)
    {
        $cachePrefix = "project_ep_all_life_statistics_{$projectId}";

        // 1、修改当前项目全生命周期数据生成状态为生成中
        $value = 'generating_' . time();
        Cache::set($cachePrefix, $value);

        // 2、发送到队列处理
        Client::send('generate_task_statistics_cache', build_queue_data_with_xu([
            'project_id' => $projectId,
        ]));
    }

    /**
     * 检测当前项目缓存是否生成
     * @param $projectId
     * @param false $returnDetails
     * @return array|bool
     */
    protected function checkProjectEpisodeTaskCycleStatisticsCache($projectId, $returnDetails = false)
    {
        $cachePrefix = "project_ep_all_life_statistics_{$projectId}";
        $cache = Cache::get($cachePrefix);

        if (!empty($cache)) {
            $array = explode('_', $cache);
            if ($array[0] === 'complete') {
                // 已经生成 判断是否过期，过期时间半个小时
                if (time() > ((int)$array[1] + 1800)) {
                    // 更新缓存
                    $this->generateProjectEpisodeTaskStatistics($projectId);
                } else {
                    if ($returnDetails) {
                        return [true, (int)$array[1]];
                    } else {
                        return true;
                    }
                }
            }
        } else {
            // 更新缓存
            $this->generateProjectEpisodeTaskStatistics($projectId);
        }

        // 缓存生成中
        if ($returnDetails) {
            return [false, 0];
        } else {
            throw_strack_exception('Cache generation in progress.', ErrorCode::TaskCycleStatisticsCacheGenerating);
        }
    }

    /**
     * @param $filter
     * @param $type
     * @return mixed|void
     */
    public function getProjectTaskAllLifeCycleStatisticsByCache($filter, $type)
    {
        list($status, $expireTime) = $this->checkProjectEpisodeTaskCycleStatisticsCache($filter['project_id'], true);
        if ($status) {
            $cachePrefix = "task_all_life_statistics_{$type}_{$filter['project_id']}_{$filter['episode_id']}";
            $cacheData = S($cachePrefix);
            if (isset($cacheData)) {
                return $cacheData;
            } else {
                // 缓存生成中
                throw_strack_exception('Cache generation in progress.', ErrorCode::TaskCycleStatisticsCacheGenerating);
            }
        }
    }

    /**
     * 获取指定项目任务全生命周期统计数据 (从镜头展开)
     * @param $filter
     * @param $shotFilter
     * @return array
     */
    public function getProjectTaskAllLifeCycleStatisticsByShot($filter, $shotFilter = [])
    {
        // 获取当前项目镜头统计工序配置
        $statisticalStepData = $this->getTemplateStatisticalStepConfig($filter['project_id'], 'shot');


        // 获取序列数据
        $sequenceIds = $this->getProjectSequenceIdsByEpisodeId($filter['episode_id']);

        /**
         * 一、查找所有镜头实体
         *
         * 1. 镜头同级别 entity_module_id（shot） 和 entity_id 相同的灯光、特效、合成是否完成
         * 2. 镜头所属序列
         * 3. 镜头同序列 entity_module_id（sequence） 和 entity_id 相同的 LayOut、动画、解算是否完成
         *
         * 4、shot_storyboard 镜头关联分镜字段
         * 5、sequence_asset 序列关联资产字段
         * 7、sequence_level 序列关联关卡字段
         * 6、asset_design 资产关联概念字段
         *
         * 二、查找集 剧本、配音、配乐、剪辑任务状态
         */

        // 查找所有镜头实体
        $entityModel = model(EntityModel::class);
        $entityShotQuery = $entityModel->field("
            id,
            name,
            entity_id,
            entity_module_id,
            JSON_UNQUOTE(JSON_EXTRACT(json, '$.shot_storyboard')) AS shot_storyboard
        ")
            ->where([
                'project_id' => $filter['project_id'],
                'module_id' => Module::$moduleDictData['module_index_by_code']['shot']['id'],
                'entity_id' => ['IN', join(',', $sequenceIds)]
            ]);

        //如果存在镜头的筛选
        if (!empty($shotFilter)) {
            $entityShotQuery->where($shotFilter);
        }

        $entityShotData = $entityShotQuery->select();


        // 所属序列ids
        $entitySequenceIds = [];

        // 镜头跟序列映射数据
        $shotSequenceMapping = [];

        // 所属分镜
        $entityStoryboardIds = [];

        // 镜头跟分镜映射数据
        $shotStoryboardMapping = [];


        foreach ($entityShotData as $entityShotItem) {
            if (!in_array($entityShotItem['entity_id'], $entitySequenceIds)) {
                $entitySequenceIds[] = $entityShotItem['entity_id'];
            }

            $shotSequenceMapping[$entityShotItem['entity_id']][] = $entityShotItem['id'];


            if (!in_array($entityShotItem['shot_storyboard'], $entityStoryboardIds)) {
                $entityStoryboardIds[] = $entityShotItem['shot_storyboard'];
            }

            $shotStoryboardMapping[$entityShotItem['id']][] = $entityShotItem['shot_storyboard'];
        }


        /**
         * 序列所属集数数据
         *
         * 序列管理这些资产也就是下面镜头都关联这些资产
         */
        $entitySequenceData = $entityModel->field("
            id,
            name,
            entity_id,
            entity_module_id,
            JSON_UNQUOTE(JSON_EXTRACT(json, '$.sequence_asset')) AS sequence_asset,
            JSON_UNQUOTE(JSON_EXTRACT(json, '$.sequence_level')) AS sequence_level
        ")
            ->where([
                'id' => ['in', join(',', $entitySequenceIds)],
            ])
            ->select();

        // 镜头所属集
        $episodeIds = [];
        $shotEpisodeMapping = [];
        $sequenceAssetMapping = [];
        $assetIds = [];

        $sequenceLevelMapping = [];
        $levelIds = [];

        foreach ($entitySequenceData as $entitySequenceItem) {
            if (!in_array($entitySequenceItem['entity_id'], $episodeIds)) {
                $episodeIds[] = $entitySequenceItem['entity_id'];
            }
            if (array_key_exists($entitySequenceItem['entity_id'], $shotEpisodeMapping)) {
                $shotEpisodeMapping[$entitySequenceItem['entity_id']] = array_merge($shotEpisodeMapping[$entitySequenceItem['entity_id']], $shotSequenceMapping[$entitySequenceItem['id']]);
            } else {
                $shotEpisodeMapping[$entitySequenceItem['entity_id']] = $shotSequenceMapping[$entitySequenceItem['id']];
            }

            if (!empty($entitySequenceItem['sequence_asset'])) {
                $sequenceAssetIds = explode(',', $entitySequenceItem['sequence_asset']);
                foreach ($sequenceAssetIds as $sequenceAssetId) {
                    if (!in_array($sequenceAssetId, $assetIds)) {
                        $assetIds[] = $sequenceAssetId;
                    }
                }

                $sequenceAssetMapping[$entitySequenceItem['id']] = $sequenceAssetIds;
            }

            if (!empty($entitySequenceItem['sequence_level'])) {
                $sequenceLevelIds = explode(',', $entitySequenceItem['sequence_level']);
                foreach ($sequenceLevelIds as $sequenceLevelId) {
                    if (!in_array($sequenceLevelId, $levelIds)) {
                        $levelIds[] = $sequenceLevelId;
                    }
                }

                $sequenceLevelMapping[$entitySequenceItem['id']] = $sequenceLevelIds;
            }
        }


        // 查询序列所属集数据
        $entityEpisodeData = $entityModel->field('id,name,entity_id,entity_module_id')->where([
            'id' => ['in', join(',', $episodeIds)]
        ])
            ->select();

        // 获取状态映射字典
        $this->getTaskStatusMapping();

        $shotTaskData = [];

        //需要拿取与镜头相关的实体数据


        // 镜头实体：灯光、特效、合成，任务完成状态
        $shotSecondLevelStepCategoryIds = $this->getEntitySecondLevelStepCategory(Module::$moduleDictData['module_index_by_code']['shot']['id']);
        $shotStepCategoryTasks = $this->getEntityStepTaskStatus($shotSecondLevelStepCategoryIds, array_column($entityShotData, 'id'));
        $this->reviseShotTaskStepCategoryData($shotTaskData, $shotStepCategoryTasks);

        // 序列实体：layout、动画、解算
        $sequenceSecondLevelStepCategoryIds = $this->getEntitySecondLevelStepCategory(Module::$moduleDictData['module_index_by_code']['sequence']['id']);
        $sequenceStepCategoryTasks = $this->getEntityStepTaskStatus($sequenceSecondLevelStepCategoryIds, array_column($entitySequenceData, 'id'));
        $this->reviseSequenceTaskStepCategoryData($shotTaskData, $sequenceStepCategoryTasks, $shotSequenceMapping);

        // 序列关联资产：sequence_asset
        $assetSecondLevelStepCategoryIds = $this->getEntitySecondLevelStepCategory(Module::$moduleDictData['module_index_by_code']['asset']['id']);
        $assetStepCategoryTasks = $this->getEntityStepTaskStatus($assetSecondLevelStepCategoryIds, $assetIds);
        $this->reviseSequenceLinkTaskStepCategoryData($shotTaskData, $assetStepCategoryTasks, $shotSequenceMapping, $sequenceAssetMapping);

        // 序列关联关卡：sequence_level
        $levelSecondLevelStepCategoryIds = $this->getEntitySecondLevelStepCategory(Module::$moduleDictData['module_index_by_code']['level']['id']);
        $levelStepCategoryTasks = $this->getEntityStepTaskStatus($levelSecondLevelStepCategoryIds, $levelIds);
        $this->reviseSequenceLinkTaskStepCategoryData($shotTaskData, $levelStepCategoryTasks, $shotSequenceMapping, $sequenceLevelMapping);

        // 通过资产查找概念
        $assetDesignDataMapping = $this->getEntityLinkEntityData($assetIds, 'asset_design');

        // 通过关卡查找概念
        $levelDesignDataMapping = $this->getEntityLinkEntityData($levelIds, 'level_design');

        // 查找概念任务数据
        $designEntityIds = [];
        foreach ($assetDesignDataMapping['link_map'] as $linkAssetDesignIds) {
            foreach ($linkAssetDesignIds as $linkAssetDesignId) {
                if (!in_array($linkAssetDesignId, $designEntityIds)) {
                    $designEntityIds[] = $linkAssetDesignId;
                }
            }
        }
        foreach ($levelDesignDataMapping['link_map'] as $linkLevelDesignIds) {
            foreach ($linkLevelDesignIds as $linkLevelDesignId) {
                if (!in_array($linkLevelDesignId, $designEntityIds)) {
                    $designEntityIds[] = $linkLevelDesignId;
                }
            }
        }
        $designSecondLevelStepCategoryIds = $this->getEntitySecondLevelStepCategory(Module::$moduleDictData['module_index_by_code']['design']['id']);
        $designStepCategoryTasks = $this->getEntityStepTaskStatus($designSecondLevelStepCategoryIds, $designEntityIds);
        $this->reviseDesignLinkTaskStepCategoryData($shotTaskData, $designStepCategoryTasks, $shotSequenceMapping, $assetDesignDataMapping['link_map'], $levelDesignDataMapping['link_map'], $sequenceAssetMapping, $sequenceLevelMapping);


        // 通过镜头查找分镜任务数据
        $storyboardSecondLevelStepCategoryIds = $this->getEntitySecondLevelStepCategory(Module::$moduleDictData['module_index_by_code']['storyboard']['id']);
        $storyboardStepCategoryTasks = $this->getEntityStepTaskStatus($storyboardSecondLevelStepCategoryIds, $entityStoryboardIds);
        $this->reviseStoryboardTaskStepCategoryData($shotTaskData, $storyboardStepCategoryTasks, $shotStoryboardMapping);


        // 统计集数维度任务：剧本、调色、配音、配乐、剪辑
        $episodeSecondLevelStepCategoryIds = $this->getEntitySecondLevelStepCategory(Module::$moduleDictData['module_index_by_code']['episode']['id']);
        $episodeStepCategoryTasks = $this->getEntityStepTaskStatus($episodeSecondLevelStepCategoryIds, $episodeIds);
        $episodeTaskData = [];
        $this->reviseEpisodeTaskStepCategoryData($episodeTaskData, $episodeStepCategoryTasks);

        $episodePlanData = $this->getEpisodePlanData($filter['project_id'], $entityEpisodeData);
        $episodeStepCategoryPlanData = $this->getEpisodeStepCategoryPlanData($filter['project_id'], $entityEpisodeData);

        return $this->generateEpisodeStatistics($statisticalStepData, [
            'episode_plan_data' => $episodePlanData,
            'episode_step_category_plan_data' => $episodeStepCategoryPlanData,
            'leaf_node_episode_mapping' => $shotEpisodeMapping,
            'episode_data' => [
                'entity_data' => $entityEpisodeData,
                'task_data' => $episodeTaskData
            ],
            'leaf_node_data' => [
                'entity_data' => $entityShotData,
                'task_data' => $shotTaskData
            ]
        ], 'shot');
    }

    /**
     * 获取指定项目任务全生命周期统计数据 (从资产展开)
     * @param $filter
     * @param $assetFilter
     * @return array
     */
    public function getProjectTaskAllLifeCycleStatisticsByAsset($filter, $assetFilter = [])
    {
        // 获取当前项目资产统计工序配置
        $statisticalStepData = $this->getTemplateStatisticalStepConfig($filter['project_id'], 'asset');

        // 获取当前这集code
//        $episodeCode = model(EntityModel::class)->where(['id' => $filter['episode_id']])->getField('code');

        /**
         * 一、查找所有资产实体
         *
         * 1、剧本人物小传 TODO
         * 2、概念
         * 3、模型
         * 4、绑定
         *
         * 二、查找所有关卡实体
         * 1、剧本 场景清单 TODO
         * 2、概念
         * 3、关卡
         */

        $assetModuleId = Module::$moduleDictData['module_index_by_code']['asset']['id'];
        $levelModuleId = Module::$moduleDictData['module_index_by_code']['level']['id'];
        $episodeModuleId = Module::$moduleDictData['module_index_by_code']['episode']['id'];
        $designModuleId = Module::$moduleDictData['module_index_by_code']['design']['id'];

        // 查找所有资产实体和关卡实体
        $entityModel = model(EntityModel::class);
        $assetAndLevelEntityQuery = $entityModel
            ->join('module on module.id = entity.module_id')
            ->join('entity_episode_relation on entity_episode_relation.entity_id = entity.id')
            ->field("
            entity.id,
            entity.name,
            entity.module_id,
            entity.initial_episode_code,
            entity_episode_relation.episode_id,
            entity.entity_id,
            entity.entity_module_id,
            JSON_UNQUOTE(JSON_EXTRACT(json, '$.asset_design')) AS asset_design,
            JSON_UNQUOTE(JSON_EXTRACT(json, '$.level_design')) AS level_design,
            JSON_UNQUOTE(JSON_EXTRACT(entity.json,CONCAT('$.',module.`code`,'_category') )) AS category,
            JSON_UNQUOTE(JSON_EXTRACT(entity.json,CONCAT('$.',module.`code`,'_grade') )) AS grade
        ")
            ->where([
                'entity.project_id' => $filter['project_id'],
                'module_id' => ["in", join(",", [$assetModuleId, $levelModuleId])],
                'entity_episode_relation.episode_id' => $filter['episode_id']
            ]);


        if (!empty($assetFilter)) {
            $assetAndLevelEntityQuery->where($assetFilter);
        }
        $assetAndLevelEntityData = $assetAndLevelEntityQuery->select();

        //多个场次可能会导致重复数据(有相同的id去重)
        $assetAndLevelEntityData = array_column($assetAndLevelEntityData, null, 'id');
        $assetAndLevelEntityData = array_values($assetAndLevelEntityData);

        // 资产和关卡所属集
        // 1、通过初始集code来查询出episode实体
        // 2、集数与资产的映射 , 资产与概念的映射

        // 任务
        // 1、资产与关卡的工序分类任务 ,得到任务中所需要的数据
        // 2、通过资产融合概念、模型、绑定任务 | 通过关卡融和概念、关卡任务| 通过集融合 资产与关卡 数据
        // 2、集数实体相关的任务: 剧本

        //最后通过集数映射匹配数据


        // 1、通过初始集code来查询出episode实体
        $initialEpisodeCode = [];
        foreach ($assetAndLevelEntityData as $assetAndLevelEntity) {
            if (!in_array($assetAndLevelEntity["initial_episode_code"], $initialEpisodeCode)) {
                $initialEpisodeCode[] = $assetAndLevelEntity["initial_episode_code"];
            }
        }

        $episodeEntityData = $entityModel->field("
            id,
            name,
            code,
            module_id,
            entity_module_id
        ")
            ->where([
                'id' => $filter['episode_id']
            ])
            ->order('id asc')
            ->select();

        $episodeIds = [];
        $episodeCodeMapping = [];
        foreach ($episodeEntityData as $episodeEntityItem) {
            if (!in_array($episodeEntityItem["id"], $episodeIds)) {
                $episodeIds[] = $episodeEntityItem["id"];
            }

            if (!in_array($episodeEntityItem["code"], $episodeCodeMapping)) {
                $episodeCodeMapping[$episodeEntityItem["code"]] = $episodeEntityItem["id"];
            }
        }

        // 2.建立映射
        // 集数与资产的映射 , 资产与概念的映射 , 资产ids ,概念ids,关卡ids
        $assetAndLevelEpisodeMapping = [];
        $levelDesignMapping = [];
        $assetDesignMapping = [];
        $assetDesignIds = [];
        $levelDesignIds = [];

        $assetIds = [];
        $levelIds = [];


        foreach ($assetAndLevelEntityData as $assetAndLevelEntityItem) {
            //资产相关映射
            if ($assetAndLevelEntityItem["module_id"] === $assetModuleId) {
                //资产ids
                if (!in_array($assetAndLevelEntityItem["id"], $assetIds)) {
                    $assetIds[] = $assetAndLevelEntityItem["id"];
                }

                //资产 概念映射
                if (!empty($assetAndLevelEntityItem["asset_design"])) {
                    $assetDesignMapping[$assetAndLevelEntityItem["id"]] = $assetAndLevelEntityItem["asset_design"];
                    $assetDesignIds[] = $assetAndLevelEntityItem["asset_design"];
                } else {
                    $assetDesignMapping[$assetAndLevelEntityItem["id"]] = [];
                }
            } elseif ($assetAndLevelEntityItem["module_id"] === $levelModuleId) {
                //关卡相关映射
                //关卡ids
                if (!in_array($assetAndLevelEntityItem["id"], $levelIds)) {
                    $levelIds[] = $assetAndLevelEntityItem["id"];
                }

                //关卡 概念映射
                if (!empty($assetAndLevelEntityItem["level_design"])) {
                    $levelDesignMapping[$assetAndLevelEntityItem["id"]] = $assetAndLevelEntityItem["level_design"];
                    $levelDesignIds[] = $assetAndLevelEntityItem["level_design"];
                } else {
                    $levelDesignMapping[$assetAndLevelEntityItem["id"]] = [];
                }
            }

            // 集与资产、关卡的映射
//            if (array_key_exists($assetAndLevelEntityItem["initial_episode_code"], $episodeCodeMapping)) {
//                if (!array_key_exists($episodeCodeMapping[$assetAndLevelEntityItem["initial_episode_code"]], $assetAndLevelEpisodeMapping)) {
//                    $assetAndLevelEpisodeMapping[$episodeCodeMapping[$assetAndLevelEntityItem["initial_episode_code"]]] = [];
//                }
//                if (!in_array($assetAndLevelEntityItem["id"], $assetAndLevelEpisodeMapping[$episodeCodeMapping[$assetAndLevelEntityItem["initial_episode_code"]]])) {
//                    $assetAndLevelEpisodeMapping[$episodeCodeMapping[$assetAndLevelEntityItem["initial_episode_code"]]][] = $assetAndLevelEntityItem["id"];
//                }
//            }
            if (!array_key_exists($assetAndLevelEntityItem['episode_id'], $assetAndLevelEpisodeMapping)) {
                $assetAndLevelEpisodeMapping[$assetAndLevelEntityItem['episode_id']] = [$assetAndLevelEntityItem["id"]];
            } else {
                $assetAndLevelEpisodeMapping[$assetAndLevelEntityItem['episode_id']][] = $assetAndLevelEntityItem["id"];
            }
        }

        //按照集的顺序来排序集对资产与关卡的映射
        ksort($assetAndLevelEpisodeMapping);


        // 获取状态映射字典
        $this->getTaskStatusMapping();

        //获取对应的字段


        // 3.查询任务
        $assetAndLevelTaskData = [];
        //资产 模型、绑定任务
        $assetSecondLevelStepCategoryIds = $this->getEntitySecondLevelStepCategory($assetModuleId);
        $assetStepCategoryTasks = $this->getEntityStepTaskStatus($assetSecondLevelStepCategoryIds, $assetIds);
        $this->reviseAssetTaskStepCategoryData($assetAndLevelTaskData, $assetStepCategoryTasks);

        //资产 概念 任务
        $designSecondLevelStepCategoryIds = $this->getEntitySecondLevelStepCategory($designModuleId);
        $assetDesignStepCategoryTasks = $this->getEntityStepTaskStatus($designSecondLevelStepCategoryIds, $assetDesignIds);
        $this->reviseAssetDesignTaskStepCategoryData($assetAndLevelTaskData, $assetDesignStepCategoryTasks, $assetDesignMapping);

        //关卡 关卡任务
        $levelSecondLevelStepCategoryIds = $this->getEntitySecondLevelStepCategory($levelModuleId);
        $levelStepCategoryTasks = $this->getEntityStepTaskStatus($levelSecondLevelStepCategoryIds, $levelIds);
        $this->reviseAssetTaskStepCategoryData($assetAndLevelTaskData, $levelStepCategoryTasks);

        //关卡 概念任务
        $levelDesignStepCategoryTasks = $this->getEntityStepTaskStatus($designSecondLevelStepCategoryIds, $levelDesignIds);
        $this->reviseAssetDesignTaskStepCategoryData($assetAndLevelTaskData, $levelDesignStepCategoryTasks, $levelDesignMapping);

        //集相关任务 剧本 TODO
        $episodeTaskData = [];

        $episodePlanData = $this->getEpisodePlanData($filter['project_id'], $episodeEntityData);
        $episodeStepCategoryPlanData = $this->getEpisodeStepCategoryPlanData($filter['project_id'], $episodeEntityData);

        // 通过 工序模板,集的映射 调整 得到相应的模板数据
        return $this->generateEpisodeStatistics($statisticalStepData, [
            'episode_plan_data' => $episodePlanData,
            'episode_step_category_plan_data' => $episodeStepCategoryPlanData,
            'leaf_node_episode_mapping' => $assetAndLevelEpisodeMapping,
            'episode_data' => [
                'entity_data' => $episodeEntityData,
                'task_data' => $episodeTaskData
            ],
            'leaf_node_data' => [
                'entity_data' => $assetAndLevelEntityData,
                'task_data' => $assetAndLevelTaskData
            ]
        ], 'asset');
    }

    /**
     * 获取集的计划时间
     * @param $project
     * @param $episodeEntityData
     * @return array|false|mixed|string
     */
    public function getEpisodePlanData($project, $episodeEntityData)
    {
        $res = [];
        if (!empty($episodeEntityData)) {
            $episodeEntityDataIds = array_column($episodeEntityData, 'id');
            $res = model(PlanModel::class)
                ->where(['project_id' => $project, 'type' => 'episode', 'entity_id' => ['IN', $episodeEntityDataIds]])
                ->field('entity_id,end_time')
                ->select();
            if (!empty($res)) {
                $res = array_column($res, 'end_time', 'entity_id');
            }
        }
        return $res;
    }

    /**
     * 获取集下的工序分类id
     * @param $project
     * @param $episodeEntityData
     * @return array
     */
    public function getEpisodeStepCategoryPlanData($project, $episodeEntityData)
    {
        $res = [];
        if (!empty($episodeEntityData)) {
            $episodeEntityDataIds = array_column($episodeEntityData, 'id');
            $data = model(PlanModel::class)
                ->where(['project_id' => $project,
                    'entity_id' => ['IN', $episodeEntityDataIds],
                    'type' => 'step_category'])
                ->field('entity_id,step_category_id,end_time')
                ->select();
            if (!empty($data)) {
                foreach ($data as $item) {
                    $res[$item['entity_id']][$item['step_category_id']] = $item['end_time'];
                }
            }
        }
        return $res;
    }

    /**
     * 获取资产关联的任务
     * @param $param
     * @return array
     */
    public function getLifeCycleStatisticsEntityTaskByAsset($param)
    {
        $entityId = $param['filter']['entity_id'];
        $stepCategoryId = $param['filter']['step_category_id'];
        $page = $param['page'] ?? [1, C("database.database_max_select_rows")];

        $currentStepCategoryId = [];
        $currentStepCategory = model(StepCategoryModel::class)->field('id,code,parent_id')->find($stepCategoryId);
        if ($currentStepCategory['parent_id'] != 0) {
            $currentSecondStepCategory = model(StepCategoryModel::class)->where(['id' => $currentStepCategory['parent_id']])->field('id,code')->find();
            $currentCode = $currentSecondStepCategory['code'];
            $currentStepCategoryId[] = $currentStepCategory['id'];
        } else {
            $currentCode = $currentStepCategory['code'];
            $currentSecondStepCategory = model(StepCategoryModel::class)->where(['parent_id' => $currentStepCategory['id']])->field('id')->select();
            $currentStepCategoryId = array_column($currentSecondStepCategory, 'id');
        }

        $entity = model(EntityModel::class)
            ->join('module on module.id = entity.module_id')
            ->field("
            entity.id,
            entity.name,
            entity.module_id,
            JSON_UNQUOTE(JSON_EXTRACT(entity.json,CONCAT('$.',module.`code`,'_design') )) AS design
        ")
            ->where(['entity.id' => $entityId])
            ->find();
        $taskData = [];
        switch ($currentCode) {
            case "level":
            case "asset":
                $taskData = $this->getTaskDetail($entity['id'], $currentStepCategoryId, $page);
                break;
            case "design":
                $taskData = $this->getTaskDetail($entity['design'], $currentStepCategoryId, $page);
                break;
        }

        return $taskData;
    }

    /**
     * 获取镜头关联的任务
     * @param $param
     * @return array
     */
    public function getLifeCycleStatisticsEntityTaskByShot($param)
    {
        $entityId = $param['filter']['entity_id'];
        $stepCategoryId = $param['filter']['step_category_id'];
        $page = $param['page'] ?? [1, C("database.database_max_select_rows")];

        $currentStepCategory = model(StepCategoryModel::class)->field('id,code,parent_id')->find($stepCategoryId);

        $currentStepCategoryId = [];
        if ($currentStepCategory['parent_id'] != 0) {
            $currentSecondStepCategory = model(StepCategoryModel::class)->where(['id' => $currentStepCategory['parent_id']])->field('id,code')->find();
            $currentCode = $currentSecondStepCategory['code'];
            $currentStepCategoryId[] = $currentStepCategory['id'];
        } else {
            $currentCode = $currentStepCategory['code'];
            $currentSecondStepCategory = model(StepCategoryModel::class)->where(['parent_id' => $currentStepCategory['id']])->field('id')->select();
            $currentStepCategoryId = array_column($currentSecondStepCategory, 'id');
        }

        $entity = model(EntityModel::class)
            ->join('module on module.id = entity.module_id')
            ->field("
            entity.id,
            entity.name,
            entity.module_id,
            entity.entity_id,
            JSON_UNQUOTE(JSON_EXTRACT(entity.json,'$.shot_storyboard')) AS shot_storyboard
        ")
            ->where(['entity.id' => $entityId])
            ->find();

        $sequenceAsset = [];
        $sequenceLevel = [];
        $designIds = [];
        if (!empty($entity['entity_id'])) {
            $sequence = model(EntityModel::class)->field(
                "id,JSON_UNQUOTE(JSON_EXTRACT(json, '$.sequence_asset')) AS sequence_asset,
                            JSON_UNQUOTE(JSON_EXTRACT(json, '$.sequence_level')) AS sequence_level"
            )->find($entity['entity_id']);
            $sequenceAsset = explode(',', $sequence['sequence_asset']);
            $sequenceLevel = explode(',', $sequence['sequence_level']);
            $sequenceEntity = array_merge($sequenceAsset, $sequenceLevel);

            if (!empty($sequenceEntity)) {
                $design = model(EntityModel::class)
                    ->join('module on module.id = entity.module_id')
                    ->where(["entity.id" => ["IN", $sequenceEntity]])
                    ->field("JSON_UNQUOTE(JSON_EXTRACT(entity.json,CONCAT('$.',module.`code`,'_design') )) AS design")
                    ->select();
                $designIds = array_column($design, 'design');
                $designIds = join(',', $designIds);
                $designIds = explode(',', $designIds);
                $designIds = array_unique($designIds);
            }
        }


        $taskData = ['total' => 0, 'rows' => []];
        switch ($currentCode) {
            case "shot":
                $taskData = $this->getTaskDetail($entity['id'], $currentStepCategoryId, $page);
                break;
            case "sequence":
                if (!empty($sequence)) {
                    $taskData = $this->getTaskDetail($sequence['id'], $currentStepCategoryId, $page);
                }
                break;
            case "level":
            case "asset":
                if (!empty($sequence)) {
                    $taskData = $this->getTaskDetail(["IN", $sequence["sequence_{$currentCode}"]], $currentStepCategoryId, $page);
                }
                break;
            case "design":
                if (!empty($designIds)) {
                    $taskData = $this->getTaskDetail(["IN", $designIds], $currentStepCategoryId, $page);
                }
                break;
            case "storyboard":
                if (!empty($entity['shot_storyboard'])) {
                    $taskData = $this->getTaskDetail($entity['shot_storyboard'], $currentStepCategoryId, $page);
                }
                break;
        }
        return $taskData;
    }

    /**
     * 获取任务详情
     * @param $entityId
     * @param $currentStepCategoryId
     * @param $page
     * @return array
     */
    public function getTaskDetail($entityId, $currentStepCategoryId, $page)
    {
        $taskCount = model(TaskModel::class)
            ->where([
                'task.entity_id' => $entityId,
                'task.step_type' => 'step_category',
                'task.step_category_id' => ["IN", join(',', $currentStepCategoryId)]
            ])
            ->count();

        $filed = "task.id,entity.name,task.code,task.entity_id,step_category.name as step_category_name,user.name as executor_name,status.name as status_name,
                     JSON_UNQUOTE(JSON_EXTRACT(entity.json,CONCAT('$.',module.`code`,'_category') )) AS category";


//        $taskData = model(TaskModel::class)
//            ->join("LEFT JOIN step_category ON step_category.id = task.step_category_id")
//            ->join("LEFT JOIN status ON status.id = JSON_UNQUOTE(JSON_EXTRACT(task.json, '$.task_status'))")
//            ->join("LEFT JOIN user ON user.id = task.executor")
//            ->join("LEFT JOIN entity ON task.entity_id = entity.id")
//            ->join('module on module.id = entity.module_id')
//            ->field()
//            ->where([
//                'task.entity_id' => $entityId,
//                'task.step_type' => 'step_category',
//                'task.step_category_id' => ["IN", join(',', $currentStepCategoryId)]
//            ])
//            ->page($page[0], $page[1])
//            ->order('task.entity_id asc')
//            ->select();

        $taskData = model(TaskModel::class)
            ->where([
                'task.entity_id' => $entityId,
                'task.step_type' => 'step_category',
                'task.step_category_id' => ["IN", join(',', $currentStepCategoryId)]
            ])
            ->field('entity_id,id as task_id')
            ->select();

        return ['total' => $taskCount, 'rows' => $taskData];
    }

    /**
     * 获取镜头的查询列表
     * @param $projectId
     * @param $filter
     * @return mixed
     */
    public function getProjectTaskAllLifeCycleStatisticsSearchListByShot($projectId, $filter)
    {
        $shotModuleId = Module::$moduleDictData['module_index_by_code']['shot']['id'];
        $episodeModuleId = Module::$moduleDictData['module_index_by_code']['episode']['id'];

        $entityModel = model(EntityModel::class);
        $entityQuery = $entityModel
            ->alias('shot')
            ->join("LEFT JOIN entity as episode ON shot.initial_episode_code = episode.code and episode.module_id= {$episodeModuleId} and episode.project_id = {$projectId}")
            ->where([
                'shot.module_id' => $shotModuleId,
                'shot.project_id' => $projectId
            ])
            ->field(
                'shot.id,shot.name,episode.name as episode_name'
            );

        if (!empty($filter)) {
            $entityQuery->where($filter);
        }
        return $entityQuery->select();
    }

    /**
     * 获取资产与关卡的查询列表
     * @param $projectId
     * @param $filter
     * @return mixed
     */
    public function getProjectTaskAllLifeCycleStatisticsSearchListByAsset($projectId, $filter)
    {
        $assetModuleId = Module::$moduleDictData['module_index_by_code']['asset']['id'];
        $levelModuleId = Module::$moduleDictData['module_index_by_code']['level']['id'];
        $episodeModuleId = Module::$moduleDictData['module_index_by_code']['episode']['id'];

        $entityModel = model(EntityModel::class);
        $entityQuery = $entityModel
            ->alias('asset')
            ->join("LEFT JOIN entity as episode ON asset.initial_episode_code = episode.code and episode.module_id= {$episodeModuleId} and episode.project_id = {$projectId}")
            ->where([
                'asset.module_id' => ["in", join(",", [$assetModuleId, $levelModuleId])],
                'asset.project_id' => $projectId,
            ])
            ->field(
                'asset.id,asset.name,episode.name as episode_name'
            );

        if (!empty($filter)) {
            $entityQuery->where($filter);
        }
        return $entityQuery->select();
    }

    /**
     * 生成集跟镜头,资产统计
     * @param $statisticalStepData
     * @param $param
     * @param string $leafNodeKey
     * @return array
     */
    protected function generateEpisodeStatistics($statisticalStepData, $param, $leafNodeKey = 'shot')
    {
        /**
         * 以镜头维度把他们整合统计
         *
         * 1、没任务 白色 待分配
         * 2、未开始 灰色 未开始
         * 3、正常 蓝色（进行中、审核）
         * 4、完成 绿色
         * 5、预警 黄色 TODO 暂时无法统计
         * 6、逾期 红色
         */
        $baseBlock = [];
        $itemBlock = [];


        foreach ($statisticalStepData as $statisticalStepItem) {
            $baseBlock[] = [
                'id' => $statisticalStepItem['id'],
                'title' => $statisticalStepItem['alias'],
                'code' => $statisticalStepItem['code'],
                'status_color' => '',
                //'data' => []
            ];

            $itemBlock[] = [
                'id' => $statisticalStepItem['id'],
                'code' => $statisticalStepItem['code'],
                'status_color' => ''
            ];
        }
        $statisticalStepDataIdMapping = array_column($statisticalStepData, null, "id");

        $resData = [];

        // 镜头数据字典
        $shotDict = array_column($param['leaf_node_data']['entity_data'], null, 'id');

        // 从集数组展开
        $entityEpisodeDict = array_column($param['episode_data']['entity_data'], null, 'id');

        //获取集的分类计划
        $episodeStepCategoryPlanData = $param['episode_step_category_plan_data'];

        foreach ($param['leaf_node_episode_mapping'] as $episodeId => $shotIds) {

            $tempData = [
                'episode' => [
                    'data' => [
                        'id' => $entityEpisodeDict[$episodeId]['id'],
                        "name" => $entityEpisodeDict[$episodeId]['name']
                    ],
                    'status' => $baseBlock
                ],
                $leafNodeKey => []
            ];

            // 当前集状态统计汇总
            $currentEpisodeSummary = [];

            foreach ($shotIds as $shotId) {
                $tmpShot = [
                    'data' => [
                        'id' => 0,
                        "name" => "",
                        "category" => "",
                        "grade" => "",
                    ],
                    'status' => $itemBlock
                ];
                if (array_key_exists($shotId, $shotDict)) {
                    $tmpShot['data']['id'] = $shotDict[$shotId]['id'];
                    $tmpShot['data']['name'] = $shotDict[$shotId]['name'];

                    if ($leafNodeKey === 'asset') {
                        $tmpShot['data']['category'] = $shotDict[$shotId]['category'];
                        $tmpShot['data']['grade'] = $shotDict[$shotId]['grade'];
                    }
                }

                foreach ($tmpShot['status'] as &$shotStatusData) {
                    $stepCategoryId = $shotStatusData['id'];

                    //填充模板默认数据
                    $shotStatusData['status_color'] = '';
//                    $shotStatusData['data'] = [
//                        'entity_task' => []
//                    ];

                    //填充data数据
                    if (array_key_exists($shotId, $shotDict)) {
                        if (array_key_exists($shotId, $param['leaf_node_data']['task_data'])) {
                            // 判断 任务中 的二级分类是否存在配置模板中
                            if (array_key_exists($stepCategoryId, $param['leaf_node_data']['task_data'][$shotId])) {
                                if (!empty($param['leaf_node_data']['task_data'][$shotId][$stepCategoryId])) {
//                                    foreach ($param['leaf_node_data']['task_data'][$shotId][$stepCategoryId]['entity_task'] as $task) {
//                                        $shotStatusData['data']['entity_task'][] = [
//                                            'entity_id' => $task['entity_id'],
//                                            'task_id' => $task['task_id']
//                                        ];
//                                    }

                                    $shotStatusData['step_end_time'] = $param['leaf_node_data']['task_data'][$shotId][$stepCategoryId]['step_end_time'];
                                    $shotStatusData['step_plan_end_time'] = $param['leaf_node_data']['task_data'][$shotId][$stepCategoryId]['step_plan_end_time'];
                                    $shotStatusData['status_color'] = $param['leaf_node_data']['task_data'][$shotId][$stepCategoryId]['color'];
                                }
                            } else {
                                //当表里的配置里有一级分类时 ,需要使用二级分类的数据去对应一级分类的数据
                                if (array_key_exists("sub_category", $statisticalStepDataIdMapping[$stepCategoryId])) {
                                    $secondStepCategory = $statisticalStepDataIdMapping[$stepCategoryId]["sub_category"];
                                    $currentTask = [];
                                    //只筛掉 只剩当前二级分类工序任务

                                    foreach ($secondStepCategory as $secondStepCategoryId) {
                                        if (array_key_exists($secondStepCategoryId, $param['leaf_node_data']['task_data'][$shotId])) {
//                                            $entityTasks = $param['leaf_node_data']['task_data'][$shotId][$secondStepCategoryId]['entity_task'];

//                                            foreach ($entityTasks as $entityTask) {
//                                                if (!empty($currentTask) && array_key_exists($entityTask['entity_id'], $currentTask)) {
//                                                    if ($entityTask['end_time'] > 0) {
//                                                        $currentTask[$entityTask['entity_id']] = [
//                                                            'entity_id' => $entityTask['entity_id'],
//                                                            'task_id' => $entityTask['task_id']
//                                                        ];
//                                                    }
//                                                } else {
//                                                    if (!empty($entityTask)) {
//                                                        $currentTask[$entityTask['entity_id']] = [
//                                                            'entity_id' => $entityTask['entity_id'],
//                                                            'task_id' => $entityTask['task_id']
//                                                        ];
//                                                    }
//                                                }
//                                            }

                                            if (!empty($shotStatusData['status_color'])) {
                                                $shotStatusData['status_color'] = $this->handlingColorConflicts($shotStatusData['status_color'], $param['leaf_node_data']['task_data'][$shotId][$secondStepCategoryId]['color']);

                                            } else {
                                                $shotStatusData['status_color'] = $param['leaf_node_data']['task_data'][$shotId][$secondStepCategoryId]['color'];

                                            }

                                            if (!isset($shotStatusData['step_end_time'])) {
                                                $shotStatusData['step_end_time'] = $param['leaf_node_data']['task_data'][$shotId][$secondStepCategoryId]['step_end_time'];
                                            } else {
                                                $shotStatusData['step_end_time'] = $this->compareTime($shotStatusData['step_end_time'], $param['leaf_node_data']['task_data'][$shotId][$secondStepCategoryId]['step_end_time']);
                                            }

                                            if (!isset($shotStatusData['step_plan_end_time'])) {
                                                $shotStatusData['step_plan_end_time'] = $param['leaf_node_data']['task_data'][$shotId][$secondStepCategoryId]['step_plan_end_time'];
                                            } else {
                                                $shotStatusData['step_plan_end_time'] = $this->compareTime($shotStatusData['step_end_time'], $param['leaf_node_data']['task_data'][$shotId][$secondStepCategoryId]['step_plan_end_time']);
                                            }
                                        }
                                    }

//                                    if (!empty($currentTask)) {
//                                        $shotStatusData['data']['entity_task'] = array_values($currentTask);
//                                    } else {
//                                        $shotStatusData['data']['entity_task'] = [];
//                                    }

                                }
                            }
                        }

                        if (empty($shotStatusData['status_color'])) {
                            $shotStatusData['status_color'] = 'white';
                        }

                        $shotStatusData['step_end_time'] = $shotStatusData['step_end_time'] ?? 0;
                        $shotStatusData['step_plan_end_time'] = $shotStatusData['step_plan_end_time'] ?? 0;

                        if (array_key_exists($stepCategoryId, $currentEpisodeSummary)) {
                            $currentEpisodeSummary[$stepCategoryId]['status_color'] = $this->handlingColorConflicts($currentEpisodeSummary[$stepCategoryId]['status_color'], $shotStatusData['status_color']);
                            $currentEpisodeSummary[$stepCategoryId]['step_end_time'] = $this->compareTime($currentEpisodeSummary[$stepCategoryId]['step_end_time'], $shotStatusData['step_end_time']);
//                            $currentEpisodeSummary[$stepCategoryId]['step_plan_end_time'] = $this->compareTime($currentEpisodeSummary[$stepCategoryId]['step_plan_end_time'], $shotStatusData['step_plan_end_time']);

                        } else {
                            $currentEpisodeSummary[$stepCategoryId]['status_color'] = $shotStatusData['status_color'];
                            $currentEpisodeSummary[$stepCategoryId]['step_end_time'] = $shotStatusData['step_end_time'];
//                            $currentEpisodeSummary[$stepCategoryId]['step_plan_end_time'] = $shotStatusData['step_plan_end_time'];
                        }
                    }
                }
                $tempData[$leafNodeKey][] = $tmpShot;
            }


            // 汇总当前集任务统计数据
            foreach ($tempData['episode']['status'] as &$data) {
                $stepCategoryId = $data['id'];
                $data['step_plan_end_time'] = $episodeStepCategoryPlanData[$episodeId][$stepCategoryId] ?? 0;
                if (array_key_exists($episodeId, $param['episode_data']['task_data']) && !empty($param['episode_data']['task_data'][$episodeId][$stepCategoryId])) {
                    //$shotStatusData['data']['entity_task'] = $param['episode_data']['task_data'][$episodeId][$stepCategoryId]['entity_task'];
                    $data['status_color'] = $param['episode_data']['task_data'][$episodeId][$stepCategoryId]['color'];
                    $data['step_end_time'] = $param['episode_data']['task_data'][$episodeId][$stepCategoryId]['step_end_time'];
                } else {
                    if (array_key_exists($stepCategoryId, $currentEpisodeSummary)) {
                        $data['status_color'] = $currentEpisodeSummary[$stepCategoryId]['status_color'];
                        $data['step_end_time'] = $currentEpisodeSummary[$stepCategoryId]['step_end_time'];
//                        $data['data'] = [
//                            'entity_task' => []
//                        ];
                    } else {
                        $data['status_color'] = 'white';
                        $data['step_end_time'] = 0;
//                        $data['data'] = [
//                            'entity_task' => []
//                        ];
                    }
                }
            }

            $resData[] = $tempData;
        }

        return $resData;
    }

    /**
     * 查询统计数据
     * @param $defaultFilter
     * @param $filter
     * @param $countType
     * @param $cacheTime
     * @return array|false|mixed|string
     */
    public function queryCountData($defaultFilter, $filter, $countType, $cacheTime)
    {
        if ($countType === 'step') {
            $res = model(EntityModel::class)
                ->join('module on module.id = entity.module_id')
                ->join('task on task.entity_id = entity.id')
                ->where($defaultFilter)
                ->where($filter)
                ->field('count(*) as count,task.step_category_id')
                ->group("task.step_category_id")
                ->cache($cacheTime)
                ->select();
        } else {
            $taskSubQuery = model(TaskModel::class)
                ->join('entity on entity.id = task.entity_id')
                ->join('module on module.id = task.entity_module_id')
                ->where($defaultFilter)
                ->field("max(task.id)")->group('task.entity_id')
                ->buildSql();
            $res = model(EntityModel::class)
                ->join('module on module.id = entity.module_id')
                ->join('INNER JOIN (select * from task where id in ' . $taskSubQuery . ' ) AS task on task.entity_id = entity.id')
                ->where($filter)
                ->field('count(*) as count,task.step_category_id')
                ->group("task.step_category_id")
                ->cache($cacheTime)
                ->select();
        }
        return $res;
    }

    /**
     * 任务完成统计
     * @param $projectId
     * @param $episodeCodes
     * @param $moduleCode
     * @param $category
     * @param $taskPlanEndTime
     * @param $stepCategoryIdFilterList
     * @param $countType
     * @return array|false|mixed|string
     */
    public function taskDoneCount($projectId, $episodeCodes, $moduleCode, $category, $taskPlanEndTime, $stepCategoryIdFilterList, $countType)
    {
        $cacheTime = 60 * 10;
        $defaultFilter = [
            'task.project_id' => $projectId,
            'task.step_type' => 'step',
        ];
        if (!empty($episodeCodes)) {
            $defaultFilter['entity.initial_episode_code'] = $episodeCodes;
        }
        if (!empty($category)) {
            $defaultFilter["JSON_UNQUOTE(JSON_EXTRACT(entity.json,CONCAT('$.', module.code, '_', 'category')))"] = $category;
        }

        $statusService = StatusService::getInstance();
        $doneStatus = $statusService->getTaskDoneStatus();
        $optionService = OptionsService::getInstance();
        $stepCategory = $optionService->getOptionsConfigItemData('assign_task_list_step_category_filter_config', $moduleCode);
        $stepCategoryIdList = explode(',', $stepCategory);
        if (!empty($stepCategoryIdFilterList)) {
            $stepCategoryIdList = array_filter($stepCategoryIdList, function ($item) use ($stepCategoryIdFilterList) {
                return in_array($item, $stepCategoryIdFilterList);
            });
        }
        $defaultFilter['task.step_category_id'] = ['IN', implode(',', $stepCategoryIdList)];
        if (!empty($taskPlanEndTime)) {
            $defaultFilter['task.plan_end_time'] = ['between', $taskPlanEndTime];
        }

        $countData = [];
        $stepCategoryList = model(StepCategoryModel::class)
            ->where(['id' => ['IN', implode(',', $stepCategoryIdList)]])
            ->field('id,name,code')
            ->order('index ASC')
            ->select();

        $doneFilter = ["_string" => "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status')) =  {$doneStatus['id']}"];
        $countData['done'] = $this->queryCountData($defaultFilter, $doneFilter, $countType, $cacheTime);
        $countData['done'] = array_column($countData['done'], 'count', 'step_category_id');


        $undoneFilter["_string"] = "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status')) is null or JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status')) <> {$doneStatus['id']}";
        $countData['undone'] = $this->queryCountData($defaultFilter, $undoneFilter, $countType, $cacheTime);
        $countData['undone'] = array_column($countData['undone'], 'count', 'step_category_id');


        $overtimeFilter = [
            '_string' => "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status')) is null or JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status')) <> {$doneStatus['id']} ",
            'task.plan_end_time' => ['LT', strtotime(date("Y-m-d"))]
        ];

        $countData['overtime'] = $this->queryCountData($defaultFilter, $overtimeFilter, $countType, $cacheTime);
        $countData['overtime'] = array_column($countData['overtime'], 'count', 'step_category_id');
        $countIndex = ['done', 'undone', 'overtime'];
        foreach ($stepCategoryList as &$stepCategory) {
            foreach ($countIndex as $index) {
                $stepCategory['data'][] = $countData[$index][$stepCategory['id']] ?? 0;
            }
        }

        return $stepCategoryList;
    }

    /**
     * 新一版的全生命周期,获取资产工序任务全生命周期
     * @param $data
     * @param $tenantId
     * @param $userId
     * @return array
     * @throws Exception
     * @throws \Exception
     */
    public function getAssetStepTaskAllLifeCycle($data, $tenantId, $userId)
    {

        $param = $data['param'];
        $type = $data['type'] ?? "step";
        $page = $param['page'] ?? [1, C('default_page_total')];
        $skipRoleDataFilter = $param['skip_role_filter'] ?? 'yes';
        $moduleCode = $data['module_code'] ?? "";
        $moduleIds = [];
        $moduleCodeStepCategory = [];
        //限制模范围大小
        if (!empty($moduleCode)) {
            $optionsService = OptionsService::getInstance();
            $options = $optionsService->getOptionsConfigItemData("merge_module_config", $moduleCode);
            $moduleCodeStepCategory = $optionsService->getOptionsConfigItemData('assign_task_list_step_category_filter_config', $moduleCode, 'shot');
            if (!empty($options)) {
                $options = explode(',', $options);
                foreach ($options as $optionItem) {
                    $moduleIds[] = module_by_code($optionItem)['id'];
                }
            }
        }

        $statusData = array_column(model(StatusModel::class)->select(), 'id', 'code');
        $filter = $param['filter'];
        $projectId = $filter['project_id'] ?? null;

        //限制项目范围大小
        if (empty($projectId)) {
            $projectList = ProjectService::getInstance()->getUserProjectList($userId, ['param' => ['project_status' => 'inprogress']]);
            $projectList = array_column($projectList['rows'], 'project');
            $projectIds = array_column($projectList, 'id');
            if (!empty($projectIds)) {
                $projectId = ["IN", $projectIds];
            }
        }

        if (!empty($projectId)) {
            $filter['task.project_id'] = $projectId;
        }

        $isFilterOverdue = $filter['is_filter_overdue'] ?? false;
        $isReceiverDeal = $filter['is_receiver_work_order'] ?? false;
        $isOwnerDeal = $filter['is_owner_work_order'] ?? false;
        $abnormal = $filter['abnormal'] ?? false;
        $isMeExecutor = $filter['is_me_executor'] ?? false;
        $isMeReview = $filter['is_me_review'] ?? false;

        //添加序列名字查询
        if ($moduleCode == 'shot' && isset($filter['sequence_name'])) {
            $sequenceList = model(EntityModel::class)
                ->where(['project_id' => $filter['project_id'], 'name' => $filter['sequence_name'], 'module_id' => module_by_code('sequence')['id']])->field('id')->select();

            if (empty($sequenceList)) {
                return [];
            }
            $sequenceIds = array_column($sequenceList, 'id');
            $filter['entity.entity_id'] = ['IN', $sequenceIds];
        }


        unset($filter['project_id'], $filter['is_filter_overdue'], $filter['sequence_name'], $filter['group_todo'], $filter['abnormal']);
        $filter = $this->parseMultipleEntityTaskFilter($filter);

        //需要特殊处理 的筛选

        if (!empty($moduleIds)) {
            $filter['entity.module_id'] = ['IN', join(',', $moduleIds)];
        }

        if (!empty($moduleCodeStepCategory)) {
            $filter['task.step_category_id'] = ['IN', $moduleCodeStepCategory];
        }

        $filter['task.step_type'] = $type;
        $filter["json_extract(entity.json, concat('$.', module.code,'_status'))"] = ['NEQ', $statusData['closed']];

        //是否查询逾期任务
        if ($isFilterOverdue) {
            //逾期有两种 完成逾期 ,未完成逾期
            //未完成逾期,判断是否有实际完成时间,计划完成时间小于当前时间
            //完成逾期,判定实际完成时间大于计划完成时间
            $statusList = StatusService::getInstance()->getTaskDefaultStatusWithExclude(['final', 'closed']);
            $statusIds = array_column($statusList, 'id');
            $filter[] = [
                "JSON_UNQUOTE(JSON_EXTRACT(task.json, '$.task_status'))" => ["IN", $statusIds],
                '_string' => "task.plan_end_time > 0 and task.plan_end_time <= " . time()
            ];
        }

        // 组内待办
        if (!empty($param['filter']['group_todo'])) {
            $departmentList = TaskAssignService::getInstance()->getAssignUserDepartmentList();
            if (empty($departmentList)) {
                return [];
            }
            $projectList = ProjectService::getInstance()->getUserProjectList($userId, ['param' => ['project_status' => 'inprogress']]);
            $projectIds = array_column(array_column($projectList['rows'], 'project'), 'id');
            $departmentIds = array_column($departmentList, 'id');
            $filter['task.department_id'] = ['IN', $departmentIds];
            if (empty($filter['task.project_id'])) {
                $filter['task.project_id'] = ['IN', $projectIds];
            }
        }
        //获取未处理状态
        $untreatedWorkOrderStatus = TaskWorkOrderService::getInstance()->getOptionsMergeItemStatus("untreated");

        if ($abnormal) { // 是否异常
            $abnormalList = model(TaskWorkOrderModel::class)
                ->where(['status' => ["IN", $untreatedWorkOrderStatus], 'tenant_id' => $tenantId, 'type' => 'task_making'])
                ->group("task_id")->select();
            if (empty($abnormalList)) {
                return [];
            }
            $abnormalId = array_column($abnormalList, 'task_id');
            $filter['task.id'] = ['IN', $abnormalId];
        }

        //是否查询自己需要处理的工单的任务
        if ($isReceiverDeal) {
            $taskIds = $this->receiverWaitDealWorkOrderTaskFilter($userId, $tenantId, $projectId, $untreatedWorkOrderStatus);
            if (empty($taskIds)) {
                return [];
            }
            $filter[]["task.id"] = ['IN', $taskIds];
        }

        //是否查询自己提交的且未处理的工单的任务
        if ($isOwnerDeal) {
            $taskIds = $this->createdByWaitDealWorkOrderTaskFilter($userId, $tenantId, $projectId, $untreatedWorkOrderStatus);
            if (empty($taskIds)) {
                return [];
            }
            $filter[]["task.id"] = ['IN', $taskIds];
        }

        // 仅我执行
        if ($isMeExecutor) {
            $filter[]['task.executor'] = $userId;
        }

        // 仅我审核
        if ($isMeReview) {
            if (empty($projectIds)) {
                $projectIds = [$projectId];
            }
            $versionData = VersionService::getInstance()->getMeExecutorReviewInfo($userId, $tenantId, $projectIds, $filter);
            if (!empty($versionData)) {
                $filter['task.id'] = ['IN', array_column($versionData, 'link_id')];
            } else {
                return [];
            }
        }

        $order = $param['order'] ?? 'entity.initial_episode_code ASC,entity.showings_number ASC,entity.name ASC';
        $taskField = ['entity.name', 'entity.code', 'entity.initial_episode_code', 'entity.showings_number', 'entity.entity_id as entity_parent_id', 'entity.step_workflow_id', 'entity.director_star', 'entity.key_shot',
            "JSON_UNQUOTE(JSON_EXTRACT(entity.json,CONCAT('$.',module.code,'_grade'))) AS grade", "JSON_UNQUOTE(JSON_EXTRACT(entity.json,CONCAT('$.',module.code,'_category'))) AS category",
            "JSON_UNQUOTE(JSON_EXTRACT(entity.json,CONCAT('$.',module.code,'_status'))) AS entity_status_id",
            'task.id', 'task.entity_id', 'task.name as task_name', 'task.plan_end_time', 'task.end_time', 'task.step_category_id', 'task.deal_status', 'task.plan_start_time', 'task.is_assignee',
            'task.assignee', 'task.executor', 'task.assignee_producer', 'task.tenant_id', 'task.executor_tenant_id', 'task.department_id', "JSON_UNQUOTE(JSON_EXTRACT(task.json, '$.task_status')) as task_status", "task.project_id",
            "task.executor_type", "JSON_UNQUOTE(JSON_EXTRACT(task.json, '$.tenant_group_id')) as tenant_group_id", 'task.updated', 'task.created_by', 'task.created', 'task.created_by as task_created_by',
            'task.episode_id', 'task.manual_man_hour',
            "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.is_dismantle_task')) AS is_dismantle_task",
            "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.parent_task_id')) AS parent_task_id",
            "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.dismantle_name')) AS dismantle_name",
            "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.shot_duration')) AS shot_duration",
            "task.assign_status,task.step_id,module.code as module_code,entity.step_workflow_id,task.actual_man_hour",
            "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_workload_remain')) as task_workload_remain",
        ];

        // 根据工单条件进行筛选任务
        $taskWorkOrderFilter = $param['filter']['task_work_order_filter'] ?? null;
        $needType = ['task_making'];
        if (!empty($taskWorkOrderFilter)) {
            $taskFilter['task.project_id'] = $filter['task.project_id'];
            if (!empty($moduleCodeStepCategory)) {
                $taskFilter['task.step_category_id'] = ['IN', $moduleCodeStepCategory];
            }
            $taskFilter['task.step_type'] = $type;

            // 筛选工单状态
            if (isset($taskWorkOrderFilter['task_work_order_status'])) {
                $taskFilter[] = ['task_work_order.status' => $taskWorkOrderFilter['task_work_order_status']];
            }
            // 筛选工单有消息
            if (isset($taskWorkOrderFilter['task_work_order_message'])) {
                $taskWorkOrderUnreadIds = $this->getTaskWorkChatIsUnread($userId, $tenantId);
                if (empty($taskWorkOrderUnreadIds)) {
                    return [];
                }
                $taskFilter[] = ['task_work_order.id' => ['IN', implode(',', $taskWorkOrderUnreadIds)]];
            }
            // 筛选任务异常状态，如果没有工单或者指定类型工单全部处理就是正常
            if (isset($taskWorkOrderFilter['is_abnormal'])) {
                $taskFilter[] = ['task_work_order.type' => ['IN', $needType], 'task_work_order.status' => ["IN", $untreatedWorkOrderStatus]];
            }
            $taskData = model(TaskModel::class)
                ->join('task_work_order on task_work_order.task_id = task.id', 'left')
                ->join('task_work_order_user on task_work_order_user.work_order_id = task_work_order.id', 'left')
                ->field('task.id as task_id,task_work_order.created_by_unread,task_work_order.receiver_unread,task_work_order.status,task_work_order.type,task_work_order.created_by,task.created_by as task_created_by')
                ->where($taskFilter)
                ->group('task_id')
                ->select();
            $taskDataIds = array_column($taskData, 'task_id');
            if (!empty($taskDataIds)) {
                $filter[]["task.id"] = ['IN', implode(',', $taskDataIds)];
            } else {
                return [];
            }
        }
        // 追加用户角色权限数据筛选
        if ($skipRoleDataFilter === 'no') {
            // 部门和角色取消了关联关系 2023年5月17日
            throw new LogicException('appendUserRoleDataFilter not support', ErrorCode::UNSUPPORTED_OPERATION);
        }
        $taskList = model(TaskModel::class)->join('entity on entity.id = task.entity_id')->join('module on entity.module_id = module.id')
            ->where($filter)->order($order)->field($taskField)->page($page[0], $page[1])->select();

        if (empty($taskList)) {
            return [];
        }

        $executorUserId = [];
        $departmentIdMap = [];
        $tenantIds = [];
        $stepCategoryIds = [];
        $entityId = [];
        $entityParentId = [];
        $insideTaskList = [];
        $submittedTaskId = [];
        $outsideTaskId = [];
        $taskStatusIds = [];
        $taskIds = [];
        $projectListIds = [];
        $tenantGroupIds = [];
        $tenantGroupTaskIds = [];
        $stepWorkFlowIdList = [];
        $episodeCodeList = [];
        //填充公司,部门,执行人
        foreach ($taskList as $taskItem) {
            if (in_array($taskItem['deal_status'], TaskModel::DEAL_STATUS_SUBMITTED_SCOPE) && !in_array($taskItem['id'], $submittedTaskId)) {
                $submittedTaskId[] = $taskItem['id'];
            }
            if ($taskItem['entity_id'] != 0 && !in_array($taskItem['entity_id'], $entityId)) {
                $entityId[] = $taskItem['entity_id'];
            }
            if ($taskItem['entity_parent_id'] != 0 && !in_array($taskItem['entity_parent_id'], $entityParentId)) {
                $entityParentId[] = $taskItem['entity_parent_id'];
            }
            if ($taskItem['step_workflow_id'] > 0 && !in_array($taskItem['step_workflow_id'], $stepWorkFlowIdList)) {
                $stepWorkFlowIdList[] = $taskItem['step_workflow_id'];
            }
            if (!empty($taskItem['initial_episode_code'])) {
                $episodeCodeList[$taskItem['initial_episode_code']] = $taskItem['initial_episode_code'];
            }

            $projectListIds[$taskItem['project_id']] = $taskItem['project_id'];

            //只有工序任务查询 公司 部门 执行人 分配人
            if ($type === 'step') {
                if (!in_array($taskItem['step_category_id'], $stepCategoryIds)) {
                    $stepCategoryIds[] = $taskItem['step_category_id'];
                }

                //其他公司不显示 执行人,部门 , 外包任务id
                //集团化的也需要获取 部门 执行人 分配人 (但是只能通过子公司的任务获取)
                if ($taskItem['executor_tenant_id'] > 0 && $taskItem['executor_tenant_id'] != $taskItem['tenant_id']) {
                    $outsideTaskId[] = $taskItem['id'];
                    $tenantIds[$taskItem['executor_tenant_id']] = $taskItem['executor_tenant_id'];
                    $tenantGroupIds[$taskItem["tenant_group_id"]] = $taskItem["tenant_group_id"];

                    if ($taskItem["executor_type"] == "tenant_group") {
                        $tenantGroupTaskIds[$taskItem["id"]] = $taskItem["id"];
                    }
                } else {
                    $insideTaskList[$taskItem['id']] = $taskItem['id'];
                    $tenantIds[$taskItem['tenant_id']] = $taskItem['tenant_id'];
                    if ($taskItem['assignee'] != 0 && !in_array($taskItem['assignee'], $executorUserId)) {
                        $executorUserId[] = $taskItem['assignee'];
                    }
                    if ($taskItem['executor'] != 0 && !in_array($taskItem['executor'], $executorUserId)) {
                        $executorUserId[] = $taskItem['executor'];
                    }
                    if ($taskItem['task_created_by'] != 0 && !in_array($taskItem['task_created_by'], $executorUserId)) {
                        $executorUserId[] = $taskItem['task_created_by'];
                    }
                    if ($taskItem['assignee_producer'] != 0 && !in_array($taskItem['assignee_producer'], $executorUserId)) {
                        $executorUserId[] = $taskItem['assignee_producer'];
                    }
                    if ($taskItem['department_id'] != 0 && !in_array($taskItem['department_id'], $departmentIdMap)) {
                        $departmentIdMap[] = $taskItem['department_id'];
                    }
                }
                if (!in_array($taskItem['created_by'], $executorUserId)) {
                    $executorUserId[] = $taskItem['created_by'];
                }

                if ($taskItem['task_status'] > 0 && !in_array($taskItem['task_status'], $taskStatusIds)) {
                    $taskStatusIds[] = $taskItem['task_status'];
                }
                if ($taskItem['entity_status_id'] > 0 && !in_array($taskItem['entity_status_id'], $taskStatusIds)) {
                    $taskStatusIds[] = $taskItem['entity_status_id'];
                }
            }
            $taskIds[] = $taskItem['id'];
        }
        $tenantGroupIds = array_values($tenantGroupIds);

        // 集查询
        $episodeList = [];
        $episodeIds = [];
        if (!empty($episodeCodeList)) {
            $episodeList = EpisodeService::getInstance()->selectEpisodeMap(['project_id' => $projectId, 'code' => ['IN', implode(',', $episodeCodeList)]]);
            $episodeIds = array_column($episodeList, "id");
        }

        //排期时间查询
        $planTimeMap = PlanService::getInstance()->getStepCategoryPlanEndTime($episodeIds, $stepCategoryIds);

        // 工序流查询
        $stepNodesDict = [];
        if (!empty($stepWorkFlowIdList)) {
            $stepNodesDict = StepWorkflowService::getInstance()->getStepNodesDictByStepWorkflowId($stepWorkFlowIdList);
        }

        $projectArray = model(ProjectModel::class)->where(["id" => ["IN", join(",", $projectListIds)]])->field("id,name,code")->select();
        $projectArray = array_column($projectArray, null, "id");

        if ($type === 'step_category') {
            //获取每个实体工序分类任务的最后一个工序任务
            list($stepTaskMap, $taskStatusIds) = $this->getStepCategoryMaxStepTaskMap($entityId);
            //追加任务状态
        }

        //查询实体的父级
        $entityParentList = [];
        if (!empty($entityParentId)) {
            $entityParentList = model(EntityModel::class)->where(['id' => ['IN', $entityParentId]])->field('id,module_id,name')->select();
            $entityParentList = array_column($entityParentList, null, 'id');
        }

        //获取外包任务映射id
        $outsideMap = ReviewTaskService::getInstance()->getOutsideMap($insideTaskList, $outsideTaskId);
        $insideTaskIdList = $outsideMap['task_ids'];
        $outsideTaskIdMap = $outsideMap['b_to_a_map'];
        $insideTaskIdMap = $outsideMap['a_to_b_map'];

        //通过外包筛选出集团任务,获取子公司的 部门 执行人 分配人
        $tenantGroupTaskIdMap = array_intersect_key($insideTaskIdMap, $tenantGroupTaskIds);
        $tenantGroupTaskList = [];
        if (!empty($tenantGroupTaskIdMap)) {

            $tenantGroupTaskIdList = array_values($tenantGroupTaskIdMap);
            $tenantGroupTaskList = model(TaskModel::class)->where(["id" => ["IN", $tenantGroupTaskIdList]])->field("id,assignee,executor,created_by as task_created_by,department_id")->select();
            foreach ($tenantGroupTaskList as $tenantGroupTaskItem) {
                if ($tenantGroupTaskItem['assignee'] != 0 && !in_array($tenantGroupTaskItem['assignee'], $executorUserId)) {
                    $executorUserId[] = $tenantGroupTaskItem['assignee'];
                }
                if ($tenantGroupTaskItem['executor'] != 0 && !in_array($tenantGroupTaskItem['executor'], $executorUserId)) {
                    $executorUserId[] = $tenantGroupTaskItem['executor'];
                }
                if ($tenantGroupTaskItem['task_created_by'] != 0 && !in_array($tenantGroupTaskItem['task_created_by'], $executorUserId)) {
                    $executorUserId[] = $tenantGroupTaskItem['task_created_by'];
                }
                if ($tenantGroupTaskItem['department_id'] != 0 && !in_array($tenantGroupTaskItem['department_id'], $departmentIdMap)) {
                    $departmentIdMap[] = $tenantGroupTaskItem['department_id'];
                }
            }
            $tenantGroupTaskList = array_column($tenantGroupTaskList, null, 'id');
        }


        $fields = [
            "review_request.id",
            "review_request.name",
            "review_request.created",
            "review_request_node.id",
            "review_request_node.is_pass",
            "review_request_node.is_reviewed",
            "review_request_node.reviewed",
            "review_request_node.start_at",
            "review_request_node.plan_reviewer",
            "review_request.link_id",
        ];
        // 审核版本map
        $reviewDataMap = [];
        //版本查询
        $maxVersion = VersionService::getInstance()->getTaskMaxVersionInfo($insideTaskIdList, "id,number,link_id,param,is_publish,is_pass,description");
        if (!empty($maxVersion)) {
            $versionModuleData = Module::$moduleDictData['module_index_by_code']['version'];
            $reviewData = model(ReviewRequestModel::class)
                ->join("review_request_node on review_request.id = review_request_node.review_request_id")
                ->where(['review_request.link_id' => ['IN', array_column($maxVersion, 'id')]])
                ->where(['review_request.module_id' => $versionModuleData['id']])
                ->where(['review_request_node.is_active' => 'yes', 'review_request.tenant_id' => $tenantId])
                ->field(build_complex_query_fields($fields, '__'))
                ->select();
            foreach ($reviewData as &$item) {
                $item = separate_complex_query_data($item, '__');
                $item['link_id'] = $item['review_request']['link_id'];
            }
            $reviewDataMap = array_column($reviewData, null, 'link_id');
        }

        $version = [];
        $submittedVersionId = [];
        foreach ($maxVersion as $maxVersionItem) {
            if (isset($outsideTaskIdMap[$maxVersionItem['link_id']])) {
                $version[$outsideTaskIdMap[$maxVersionItem['link_id']]] = $maxVersionItem;
            } else {
                $version[$maxVersionItem['link_id']] = $maxVersionItem;
            }

            if (in_array($maxVersionItem['link_id'], $submittedTaskId)) {
                $submittedVersionId[] = $maxVersionItem['id'];
            }
        }

        //审核进度查询
        $versionReviewRequestMap = [];
        $reviewRequestNodeGroup = [];
        if (!empty($submittedVersionId)) {
            $reviewInfo = $this->getReviewInfo($tenantId, $submittedVersionId);
            $versionReviewRequestMap = $reviewInfo['version_review_request_map'];
            $reviewRequestNodeGroup = $reviewInfo['review_request_node_group'];
        }

        //工单查询
        $taskWorkTypeScope = ["task_making", "review_feedback"];
        $lastTaskWorkOrderMaxIds = model(TaskWorkOrderModel::class)
            ->where(['task_id' => ['IN', $taskIds], 'type' => ["IN", $taskWorkTypeScope]])
            ->field('task_id,MAX(id) as id')->group('task_id,type')->select();

        //接受人工单 用于判定当前用户是否处理过工单 , 处理过的有记录按钮

        $lastTaskWorkOrderIds = [];
        $lastWorkOrderIdTaskIdMap = [];
        foreach ($lastTaskWorkOrderMaxIds as $lastTaskWorkOrderMaxId) {
            $lastTaskWorkOrderIds[] = $lastTaskWorkOrderMaxId['id'];
            $lastWorkOrderIdTaskIdMap[$lastTaskWorkOrderMaxId['id']] = $lastTaskWorkOrderMaxId['task_id'];
        }

        //工单的小红点提醒 ,当前用户的提醒
        $taskUnreadIds = [];
        if (!empty($lastTaskWorkOrderIds)) {
            //获取会话的未读消息
            $taskWorkOrderUnreadIds = $this->getTaskWorkChatIsUnread($userId, $tenantId, $lastTaskWorkOrderIds);
            foreach ($taskWorkOrderUnreadIds as $taskWorkOrderUnreadId) {
                if (isset($lastWorkOrderIdTaskIdMap[$taskWorkOrderUnreadId])) {
                    $taskUnreadIds[$lastWorkOrderIdTaskIdMap[$taskWorkOrderUnreadId]] = $lastWorkOrderIdTaskIdMap[$taskWorkOrderUnreadId];
                }
            }
        }

        $taskWorkOrderShow = model(TaskWorkOrderModel::class)
            ->join("task_work_order_user on task_work_order_user.work_order_id = task_work_order.id")
            ->where(["task_work_order.task_id" => ["IN", $taskIds], "task_work_order_user.user_id" => $userId, 'task_work_order.type' => ["IN", $taskWorkTypeScope]])
            ->group("task_id")->field("task_id")->select();
        $taskWorkOrderShow = array_column($taskWorkOrderShow, 'task_id', 'task_id');

        $taskWorkOrderStatusMap = [];
        $taskWorkOrderAbnormal = [];
        if (!empty($lastTaskWorkOrderIds)) {
            $taskWorkOrderList = model(TaskWorkOrderModel::class)->where(['id' => ['IN', $lastTaskWorkOrderIds]])
                ->field('id,task_id,status,type,created_by,receiver,receiver_unread,created_by_unread')->select();


            foreach ($taskWorkOrderList as $taskWorkOrderListItem) {
                if (!isset($taskWorkOrderStatusMap[$taskWorkOrderListItem['task_id']])) {
                    $taskWorkOrderStatusMap[$taskWorkOrderListItem['task_id']] = ['status' => $taskWorkOrderListItem['status']];
                } else {
                    // 状态优先级覆盖
                    $taskWorkOrderStatusMap[$taskWorkOrderListItem['task_id']]['status'] =
                        $this->taskWorkOrderStatusOrder($taskWorkOrderStatusMap[$taskWorkOrderListItem['task_id']]['status'], $taskWorkOrderListItem['status']);
                }

                // 是否异常
                if (!isset($taskWorkOrderAbnormal[$taskWorkOrderListItem['task_id']])) {
                    $taskWorkOrderAbnormal[$taskWorkOrderListItem['task_id']] = $taskWorkOrderListItem['status'];
                } else if (in_array($taskWorkOrderListItem['type'], $needType)) {
                    $taskWorkOrderAbnormal[$taskWorkOrderListItem['task_id']] =
                        $this->taskWorkOrderStatusOrder($taskWorkOrderAbnormal[$taskWorkOrderListItem['task_id']], $taskWorkOrderListItem['status']);
                }

                // 是否能上传 (最新工单为关闭状态,或者不存在最新的任务制作工单)
                if (!isset($taskWorkOrderStatusMap[$taskWorkOrderListItem['task_id']]["is_upload_task_making"]) ||
                    $taskWorkOrderStatusMap[$taskWorkOrderListItem['task_id']]["is_upload_task_making"] === false) {
                    $taskWorkOrderStatusMap[$taskWorkOrderListItem['task_id']]["is_upload_task_making"] =
                        $taskWorkOrderListItem["type"] === "task_making" && !in_array($taskWorkOrderListItem['status'], $untreatedWorkOrderStatus);
                }

                // 判断是否未处理
                if (!isset($taskWorkOrderStatusMap[$taskWorkOrderListItem['task_id']]["is_not_processed"]) ||
                    $taskWorkOrderStatusMap[$taskWorkOrderListItem['task_id']]["is_not_processed"] === false
                ) {
                    $taskWorkOrderStatusMap[$taskWorkOrderListItem['task_id']]["is_not_processed"] =
                        $taskWorkOrderListItem['receiver'] === $userId && in_array($taskWorkOrderListItem['status'], $untreatedWorkOrderStatus);
                }
            }
        }

        $userInfo = TaskService::getInstance()->queryTaskSupplierInfo($tenantId, [], [], $departmentIdMap, $executorUserId, array_values($tenantIds), $tenantGroupIds);
        if (!empty($userInfo["tenant_group"])) {
            $userInfo["tenant_group"] = array_column($userInfo["tenant_group"], null, 'id');
        }

        $statusList = [];
        if (!empty($taskStatusIds)) {
            $statusList = model(StatusModel::class)->where(['id' => ['IN', $taskStatusIds]])->field('id,name,code,color,icon')->select();
            $statusList = array_column($statusList, null, 'id');
        }

        // 填充 step
        $stepDict = [];
        $stepIds = array_column($taskList, 'step_id');
        if (!empty($stepIds)) {
            $stepData = model(StepModel::class)->field('id,name,code,color,can_multiple_submit,need_assemble')->where(['id' => ['IN', join(',', $stepIds)]])->select();
            $stepDict = array_column($stepData, null, 'id');
        }

        // 获取所有子任务
        $dismantleTaskData = DismantleTaskService::getInstance()->getDismantleTaskIds(array_column($taskList, 'id'));
        $dismantleTaskList = array_group_by($dismantleTaskData, 'source_task_id');

        // 查询任务属性字符串
        //task attr
        $taskAttr = InsideTaskReviewWorkflowService::getInstance()->getMultipleTaskAttr($taskIds);

        $taskHistoryExecutorData = [];
        if (!empty($taskList[0]['id'])) { // 任务卡片里的历史执行人,永远只查一条
            $taskHistoryExecutorData = TaskService::getInstance()->getTaskExecutorRecords($taskList[0]['id']);
            $workRecordTimeData = WorkTimeRecordService::getInstance()->getTaskWorkTimeRecord($taskList[0]['id']);
            $cumulativeWorkTime = $workRecordTimeData['count_sum'] ?? 0;
        }

        // 查询是否延期审核
        $taskDelayMap = ReviewTaskDelayService::getInstance()->taskDelayInfo($taskIds);

        //补充 任务状态,版本,执行人,分配人,部门,租户 信息
        $taskDealFunction = function ($taskItem) use ($statusList, $entityParentList, $projectArray, $episodeList, $dismantleTaskList, $taskAttr, $stepNodesDict, $taskHistoryExecutorData, $cumulativeWorkTime, $taskDelayMap) {
            $taskItem['status'] = $statusList[$taskItem['task_status']] ?? null;
            $taskItem['entity_status'] = $statusList[$taskItem['entity_status_id']] ?? null;
            $taskItem['task_attr'] = $taskAttr[$taskItem['id']] ?? '';
            //填充父级实体
            if ($taskItem['entity_parent_id'] > 0 && isset($entityParentList[$taskItem['entity_parent_id']])) {
                $entityParentModuleCode = module_by_id($entityParentList[$taskItem['entity_parent_id']]['module_id'])['code'];
                unset($entityParentList[$taskItem['entity_parent_id']]['module_id']);
                $taskItem[$entityParentModuleCode] = $entityParentList[$taskItem['entity_parent_id']];
            }

            if (isset($projectArray[$taskItem['project_id']])) {
                $taskItem['project'] = $projectArray[$taskItem['project_id']];
            }
            $taskItem['episode_id'] = $episodeList[$taskItem['initial_episode_code']]['id'] ?? '';
            $taskItem['dismantle_task_ids'] = $dismantleTaskList[$taskItem['id']] ?? [];
            $taskItem['module_code'] = in_array($taskItem['module_code'], ['design', 'asset', 'level', '']) ? 'asset' : 'shot';
            $taskItem['is_dismantle_task'] = $taskItem['is_dismantle_task'] ? (bool)$taskItem['is_dismantle_task'] : false;
            $taskItem['in_step_workflow'] = true;
            if ($taskItem['step_workflow_id'] > 0 && !empty($stepNodesDict[$taskItem['step_workflow_id']]) && !in_array($taskItem['step_id'], $stepNodesDict[$taskItem['step_workflow_id']]['step_id_list'])) {
                $taskItem['in_step_workflow'] = false;
            }
            // 历史执行人
            $taskItem['executor_records'] = $taskHistoryExecutorData;
            // 累计工时
            $taskItem['cumulative_work_time'] = $cumulativeWorkTime;
            unset($taskItem['assignee'], $taskItem['executor'], $taskItem['executor_tenant_id'], $taskItem['tenant_id'], $taskItem['department_id'], $taskItem['entity_parent_id']);
            // 是否有申请延期中
            $taskItem['is_task_delay'] = !empty($taskDelayMap[$taskItem['id']]);
            return $taskItem;
        };

        $taskDealStepCategoryFunction = $taskDealFunction;
        if ($type === 'step_category') {
            $taskDealFunction = function ($taskItem) use (&$taskDealStepCategoryFunction, &$stepTaskMap) {
                if (!empty($stepTaskMap[$taskItem['entity_id']][$taskItem['step_category_id']])) {
                    $taskItem['task_status'] = $stepTaskMap[$taskItem['entity_id']][$taskItem['step_category_id']]['task_status'];
                    $taskItem['plan_end_time'] = $stepTaskMap[$taskItem['entity_id']][$taskItem['step_category_id']]['plan_end_time'];
                    $taskItem['plan_start_time'] = $stepTaskMap[$taskItem['entity_id']][$taskItem['step_category_id']]['plan_start_time'];
                    $taskItem['end_time'] = $stepTaskMap[$taskItem['entity_id']][$taskItem['step_category_id']]['end_time'];
                }
                return $taskDealStepCategoryFunction($taskItem);
            };
        } elseif ($type === 'step') { //工序需要补充工序分类名称
            //补充工序分类名称
            $stepCategory = [];
            if (!empty($stepCategoryIds)) {
                $stepCategory = model(StepCategoryModel::class)->where(['id' => ['IN', $stepCategoryIds]])->field('id,name')->select();
                $stepCategory = array_column($stepCategory, null, 'id');
            }

            $taskDealFunction = function ($taskItem) use (
                &$taskDealStepCategoryFunction, $stepCategory, $userInfo, $version,
                $versionReviewRequestMap, $reviewRequestNodeGroup, $taskWorkOrderStatusMap, $taskUnreadIds,
                $taskWorkOrderAbnormal, $taskWorkOrderShow, $untreatedWorkOrderStatus,
                $tenantGroupTaskIdMap, $tenantGroupTaskList, $reviewDataMap, $tenantId, $stepDict, $planTimeMap
            ) {
                $taskItem['step_category_name'] = $stepCategory[$taskItem['step_category_id']]['name'];

                // 公司 部门 执行人 分配人 分配制片
                $currentTenant = $taskItem['tenant_id'];
                $taskItem['assignee_info'] = $taskItem['executor_info'] = $taskItem['department_info'] = $taskItem['created_by_info'] = null;
                $taskItem['created_by_info'] = $userInfo['executor'][$taskItem['created_by']] ?? null;
                if ($taskItem['executor_tenant_id'] > 0 && $taskItem['executor_tenant_id'] != $taskItem['tenant_id']) {
                    $currentTenant = $taskItem['executor_tenant_id'];

                    if (!empty($userInfo["tenant_group"][$taskItem["tenant_group_id"]])) {
                        $taskItem["tenant_group"] = $userInfo["tenant_group"][$taskItem["tenant_group_id"]];
                    }

                    if ($taskItem["executor_type"] == "tenant_group" && isset($tenantGroupTaskIdMap[$taskItem["id"]]) && isset($tenantGroupTaskList[$tenantGroupTaskIdMap[$taskItem["id"]]])) {
                        $currentTaskItem = $tenantGroupTaskList[$tenantGroupTaskIdMap[$taskItem["id"]]];
                        $taskItem['assignee_info'] = $userInfo['executor'][$currentTaskItem['assignee']] ?? null;
                        $taskItem['executor_info'] = $userInfo['executor'][$currentTaskItem['executor']] ?? null;
                        $taskItem['created_by_info'] = $userInfo['executor'][$currentTaskItem['task_created_by']] ?? null;
                        $taskItem['department_info'] = $userInfo['department'][$currentTaskItem['department_id']] ?? null;
                    }
                } else {
                    $taskItem['assignee_info'] = $userInfo['executor'][$taskItem['assignee']] ?? null;
                    $taskItem['executor_info'] = $userInfo['executor'][$taskItem['executor']] ?? null;
                    $taskItem['created_by_info'] = $userInfo['executor'][$taskItem['task_created_by']] ?? null;
                    $taskItem['department_info'] = $userInfo['department'][$taskItem['department_id']] ?? null;
                }

                $taskItem["assignee_producer"] = $userInfo['executor'][$taskItem['assignee_producer']] ?? null;

                $taskItem['tenant_info'] = $userInfo['tenant'][$currentTenant] ?? null;
                $taskItem['version'] = $version[$taskItem['id']] ?? null;

                //补充审核进度
                $taskItem['review_progress'] = null;
                if (isset($version[$taskItem['id']]) && isset($versionReviewRequestMap[$version[$taskItem['id']]['id']])
                    && isset($reviewRequestNodeGroup[$versionReviewRequestMap[$version[$taskItem['id']]['id']]])) {
                    $taskItem['review_progress'] = $reviewRequestNodeGroup[$versionReviewRequestMap[$version[$taskItem['id']]['id']]];
                }
                //补充工单处理状态
                $taskItem['task_work_order_status'] = $taskWorkOrderStatusMap[$taskItem['id']]['status'] ?? null;

                // 补充工单是否显示查看按钮状态
                $taskItem['task_work_order_show'] = isset($taskWorkOrderShow[$taskItem['id']]);

                //补充任务异常状态,默认是正常
                $taskItem['is_abnormal'] = isset($taskWorkOrderAbnormal[$taskItem['id']])
                && in_array($taskWorkOrderAbnormal[$taskItem['id']], TaskWorkOrderModel::STATUS_NOT_CLOSED_GROUP) ? 0 : 1;

                //是否能上传任务制作的工单
                $taskItem['is_upload_task_making'] = !isset($taskWorkOrderStatusMap[$taskItem['id']]) || $taskWorkOrderStatusMap[$taskItem['id']]['is_upload_task_making'];

                //工单小红点
                $taskItem['work_order_record_unread'] = isset($taskUnreadIds[$taskItem['id']]);

                // 处理按钮
                $taskItem['deal_task_work'] = isset($taskWorkOrderStatusMap[$taskItem['id']]) && $taskWorkOrderStatusMap[$taskItem['id']]['is_not_processed'];

                //处理按钮小红点
                $taskItem['deal_task_work_unread'] = isset($taskUnreadIds[$taskItem['id']]);

                $linkId = $taskItem['version']['id'] ?? '';
                // 审核信息
                $taskItem['review_request'] = $reviewDataMap[$linkId]['review_request'] ?? null;

                // 审核节点信息
                $taskItem['review_request_node'] = $reviewDataMap[$linkId]['review_request_node'] ?? null;

                // 是否外包
                $taskItem['is_outside'] = false;
                if ($taskItem['executor_tenant_id'] > 0 && $taskItem['executor_tenant_id'] != $tenantId) {
                    $taskItem['is_outside'] = true;
                }

                // 工序
                $taskItem['step'] = $stepDict[$taskItem['step_id']] ?? null;
                // 工作量剩余
                $taskItem['task_workload_remain'] = !is_null($taskItem['task_workload_remain']) ? intval($taskItem['task_workload_remain']) : 100;
                // 计划交付时间
                $taskItem['plan_delivery_time'] = $planTimeMap[$taskItem['episode_id']][$taskItem['step_category_id']] ?? 0;
                return $taskDealStepCategoryFunction($taskItem);
            };
        }


        return array_map($taskDealFunction, $taskList);
    }

    /**
     * 工单处理状态展示顺序
     * @param $oldStatus
     * @param $newStatus
     * @return mixed
     */
    public function taskWorkOrderStatusOrder($oldStatus, $newStatus)
    {
        // 顺序 0-未处理 1-以处理 2-以失效
        return min($oldStatus, $newStatus);
    }

    /**
     * 获取审核信息
     * @param $tenantId
     * @param $versionId
     * @return array|array[]
     * @throws \Exception
     */
    public function getReviewInfo($tenantId, $versionId)
    {
        //当前公司审核人员的进度
        $playlistItemVersion = model(PlaylistItemVersionModel::class)->where(['tenant_id' => $tenantId, 'version_id' => ['IN', $versionId]])
            ->field('version_id,review_request_id,current_review_code')->select();


        if (empty($playlistItemVersion)) {
            return ['version_review_request_map' => [], 'review_request_node_group' => []];
        }

        $reviewRequestIds = [];
        $versionReviewRequestMap = [];
        $reviewRequestCurrentCodeMap = [];
        foreach ($playlistItemVersion as $playlistItemVersionItem) {
            $reviewRequestIds[] = $playlistItemVersionItem['review_request_id'];
            $reviewRequestCurrentCodeMap[$playlistItemVersionItem['review_request_id']] = $playlistItemVersionItem['current_review_code'];
            $versionReviewRequestMap[$playlistItemVersionItem['version_id']] = $playlistItemVersionItem['review_request_id'];
        }

        $reviewRequestNodeList = model(ReviewRequestNodeModel::class)
            ->where(['review_request_id' => ['IN', $reviewRequestIds]])->field('parent_id,role_code,review_request_id,plan_reviewer')->select();

        if (empty($reviewRequestNodeList)) {
            return ['version_review_request_map' => [], 'review_request_node_group' => []];
        }

        $reviewRequestNodeGroup = ReviewTaskService::getInstance()->dealReviewSchedule($reviewRequestNodeList, $reviewRequestCurrentCodeMap);

        return ['version_review_request_map' => $versionReviewRequestMap, 'review_request_node_group' => $reviewRequestNodeGroup];
    }

    /**
     * 获取实体工序分类的最后一个工序任务的映射
     */
    public function getStepCategoryMaxStepTaskMap($entityId)
    {
        $stepMaxTask = model(TaskModel::class)
            ->where(['task.entity_id' => ['IN', $entityId], 'task.step_type' => 'step'])
            ->field('max(id) as id')->group('entity_id,step_category_id')->select();

        $stepTaskMap = [];
        $taskStatusIds = [];
        if (!empty($stepMaxTask)) {
            $stepMaxTaskIds = array_column($stepMaxTask, 'id');
            $stepTask = model(TaskModel::class)
                ->where(['task.id' => ['IN', $stepMaxTaskIds]])
                ->field("task.entity_id,task.step_category_id,task.plan_end_time,task.plan_start_time,task.end_time,task.assignee,
                JSON_UNQUOTE(JSON_EXTRACT(json,'$.task_status')) as task_status")->select();

            foreach ($stepTask as $stepTaskItem) {
                if ($stepTaskItem['task_status'] > 0 && !in_array($stepTaskItem['task_status'], $taskStatusIds)) {
                    $taskStatusIds[] = $stepTaskItem['task_status'];
                }

                if (empty($stepTaskMap[$stepTaskItem['entity_id']])) {
                    $stepTaskMap[$stepTaskItem['entity_id']] = [$stepTaskItem['step_category_id'] => $stepTaskItem];
                } else {
                    $stepTaskMap[$stepTaskItem['entity_id']][$stepTaskItem['step_category_id']] = $stepTaskItem;
                }
            }
        }

        return [$stepTaskMap, $taskStatusIds];
    }

    /**
     * 新一版的全生命周期,获取镜头工序任务全生命周期
     * @param $data
     * @param $tenantId
     * @param $userId
     * @return array
     * @throws Exception
     * @throws \Exception
     */
    public function getShotStepTaskAllLifeCycle($data, $tenantId, $userId)
    {
        /**
         * 按任务名去查找的有两种 (1.按序列 2.按镜头  默认不传任务名按序列查询)
         *  一 (按序列查询) :
         *  1.通过序列查找到镜头列表
         *  2.需要将镜头里的任务批量处理，填充序列任务（往前填入）
         *  3.在将序列循环，填入镜头列表
         * 二 （按镜头查询）：
         *  1.通过镜头反查询出序列
         *  2.镜头查出序列任务，将镜头里的任务批量处理，填充序列任务（往前填入）
         */

        $param = $data['param'];
        $type = $data['type'];
        $page = $param['page'] ?? [1, C('default_page_total')];
        $filter = $param['filter'];

        $sequenceModuleId = module_by_code('sequence')['id'];
        $shotModuleId = module_by_code('shot')['id'];


        $sequenceFilter = $filter;
        $sequenceFilter['module_id'] = $sequenceModuleId;

        // 通过镜头查出 所需的序列筛选条件
        $shotIds = [];
        if (isset($filter['shot_name'])) {
            $shotFilter = [
                'project_id' => $filter['project_id'],
                'module_id' => $shotModuleId,
                'name' => $filter['shot_name']
            ];
            //查询镜头列表
            $shotEntityList = model(EntityModel::class)->where($shotFilter)->field('id,name,entity_id')->select();
            if (empty($shotEntityList)) {
                return [];
            }

            // 通过镜头获取序列实体
            $sequenceEntityIds = [];
            foreach ($shotEntityList as $shotEntityListItem) {
                if ($shotEntityListItem['entity_id'] != 0 && !in_array($shotEntityListItem['entity_id'], $sequenceEntityIds)) {
                    $sequenceEntityIds[] = $shotEntityListItem['entity_id'];
                }
                $shotIds[] = $shotEntityListItem['id'];
            }
            if (empty($sequenceEntityIds)) {
                return [];
            }
            $sequenceFilter['id'] = ['IN', $sequenceEntityIds];
        }
        unset($sequenceFilter['shot_name']);
        //1.查出序列
        $sequenceEntityList = model(EntityModel::class)->where($sequenceFilter)
            ->page($page[0], $page[1])->field('id,name,initial_episode_code,showings_number')->select();
        if (empty($sequenceEntityList)) {
            return [];
        }

        $sequenceEntityIds = array_column($sequenceEntityList, 'id');
        $shotEntityFilter = ['entity_id' => ['IN', $sequenceEntityIds], 'module_id' => $shotModuleId];
        if (!empty($shotIds)) {
            $shotEntityFilter['id'] = ['IN', $shotIds];
        }

        //TODO 待优化 镜头可从上面的 shotEntityList里获取
        $shotEntityList = model(EntityModel::class)->where($shotEntityFilter)->field('id,name,entity_id')->select();

        //2.查出镜头
        $shotEntityIds = array_column($shotEntityList, 'id');
        $entityIds = array_merge($sequenceEntityIds, $shotEntityIds);
        if (empty($entityIds)) {
            return [];
        }

        //2.获取实体与镜头的任务
        // step category 任务 提前获取 step任务 用于补充step_category status,plan_end_time,end_time
        $taskField = ['task.id', 'task.entity_id', 'task.name', 'task.plan_end_time', 'task.plan_start_time', 'task.end_time', 'task.step_category_id', 'task.deal_status',
            'task.assignee', 'task.executor', 'task.tenant_id', 'task.executor_tenant_id', 'task.department_id', "JSON_UNQUOTE(JSON_EXTRACT(json, '$.task_status')) as task_status"
        ];

        $stepTaskMap = [];
        if ($type === 'step_category') {
            //获取每个实体工序分类任务的最后一个工序任务
            $stepTaskMap = $this->getStepCategoryMaxStepTaskMap($entityIds);
        }

        $task = model(TaskModel::class)->where(['entity_id' => ['IN', $entityIds], 'step_type' => $type])->field($taskField)->select();

        if (empty($task)) {
            return [];
        }

        $executorUserId = [];
        $departmentIdMap = [];
        $tenantIds = [];
        $stepCategoryIds = [];
        $entityId = [];
        $insideTaskList = [];
        $submittedTaskId = [];
        $outsideTaskId = [];
        $taskIds = [];
        //填充公司,部门,执行人
        foreach ($task as $taskItem) {
            if (in_array($taskItem['deal_status'], TaskModel::DEAL_STATUS_SUBMITTED_SCOPE) && !in_array($taskItem['id'], $submittedTaskId)) {
                $submittedTaskId[] = $taskItem['id'];
            }
            if ($taskItem['entity_id'] != 0 && !in_array($taskItem['entity_id'], $entityId)) {
                $entityId[] = $taskItem['entity_id'];
            }
            if ($type === 'step' && !in_array($taskItem['step_category_id'], $stepCategoryIds)) {
                $stepCategoryIds[] = $taskItem['step_category_id'];
            }

            $taskIds[] = $taskItem['id'];
            //其他公司不显示 执行人,部门 , 外包任务id
            if ($taskItem['executor_tenant_id'] > 0 && $taskItem['executor_tenant_id'] != $taskItem['tenant_id']) {
                $outsideTaskId[] = $taskItem['id'];
                $tenantIds[$taskItem['executor_tenant_id']] = $taskItem['executor_tenant_id'];
            } else {
                $insideTaskList[$taskItem['id']] = $taskItem['id'];
                $tenantIds[$taskItem['tenant_id']] = $taskItem['tenant_id'];
                if ($taskItem['assignee'] != 0 && !in_array($taskItem['assignee'], $executorUserId)) {
                    $executorUserId[] = $taskItem['assignee'];
                }
                if ($taskItem['executor'] != 0 && !in_array($taskItem['executor'], $executorUserId)) {
                    $executorUserId[] = $taskItem['executor'];
                }
                if ($taskItem['department_id'] != 0 && !in_array($taskItem['department_id'], $departmentIdMap)) {
                    $departmentIdMap[] = $taskItem['department_id'];
                }
            }
        }

        //获取外包任务映射id
        $outsideMap = ReviewTaskService::getInstance()->getOutsideMap($insideTaskList, $outsideTaskId);
        $insideTaskIdList = $outsideMap['task_ids'];
        $outsideTaskIdMap = $outsideMap['b_to_a_map'];

        //版本查询
        $maxVersion = VersionService::getInstance()->getTaskMaxVersionInfo($insideTaskIdList, "id,number,link_id");

        $version = [];
        $submittedVersionId = [];
        foreach ($maxVersion as $maxVersionItem) {
            if (isset($outsideTaskIdMap[$maxVersionItem['link_id']])) {
                $version[$outsideTaskIdMap[$maxVersionItem['link_id']]] = $maxVersionItem;
            } else {
                $version[$maxVersionItem['link_id']] = $maxVersionItem;
            }

            if (in_array($maxVersionItem['link_id'], $submittedTaskId)) {
                $submittedVersionId[] = $maxVersionItem['id'];
            }
        }

        //审核进度查询
        $versionReviewRequestMap = [];
        $reviewRequestNodeGroup = [];
        if (!empty($submittedVersionId)) {
            $reviewInfo = $this->getReviewInfo($tenantId, $submittedVersionId);
            $versionReviewRequestMap = $reviewInfo['version_review_request_map'];
            $reviewRequestNodeGroup = $reviewInfo['review_request_node_group'];
        }


        //工单查询
        $lastTaskWorkOrderMaxIds = model(TaskWorkOrderModel::class)->where(['task_id' => ['IN', $taskIds]])
            ->field('task_id,MAX(id) as id')->group('task_id,type')->select();

        //接受人工单
        $receiverTaskWorkOrderMaxIds = model(TaskWorkOrderModel::class)->where(['task_id' => ['IN', $taskIds], 'receiver' => $userId])
            ->field('MAX(id) as id')->group('task_id,type')->select();


        $lastTaskWorkOrderIds = array_column($lastTaskWorkOrderMaxIds, 'id');
        $receiverTaskWorkOrderIds = array_column($receiverTaskWorkOrderMaxIds, 'id');
        $taskWorkOrderIds = array_merge($lastTaskWorkOrderIds, $receiverTaskWorkOrderIds);

        $taskWorkOrderStatusMap = [];
        $taskMakingWorkOrder = [];
        $createdByOrderTask = [];
        $receiverOrderTask = [];
        if (!empty($taskWorkOrderIds)) {
            $taskWorkOrderList = model(TaskWorkOrderModel::class)->where(['id' => ['IN', $taskWorkOrderIds]])
                ->field('task_id,status,type,created_by,receiver,receiver_unread,created_by_unread')->select();

            foreach ($taskWorkOrderList as $taskWorkOrderListItem) {
                if (!isset($taskWorkOrderStatusMap[$taskWorkOrderListItem['task_id']])) {
                    $taskWorkOrderStatusMap[$taskWorkOrderListItem['task_id']] = $taskWorkOrderListItem['status'];
                } else {
                    $taskWorkOrderStatusMap[$taskWorkOrderListItem['task_id']] =
                        $this->taskWorkOrderStatusOrder($taskWorkOrderStatusMap[$taskWorkOrderListItem['task_id']], $taskWorkOrderListItem['status']);
                }

                //是否能上传 (最新工单为关闭状态,或者不存在最新的任务制作工单)
                if ($taskWorkOrderListItem['status'] === TaskWorkOrderModel::STATUS_UNTREATED) {
                    if ($taskWorkOrderListItem["type"] === "task_making") {
                        $taskMakingWorkOrder[] = $taskWorkOrderListItem['task_id'];
                    }

                    //工单小红点
                    if ($taskWorkOrderListItem['created_by'] === $userId && $taskWorkOrderListItem["created_by_unread"] === "yes" &&
                        !in_array($taskWorkOrderListItem['task_id'], $createdByOrderTask)) {
                        $createdByOrderTask[] = $taskWorkOrderListItem['task_id'];
                    }
                }

                //处理按钮判断逻辑 判断接受是否有存在的未处理的工单 , 判断status状态为 未处理状态 显示处理按钮 , 若都为已处理 则显示记录按钮, 没有则不显示
                if ($taskWorkOrderListItem['receiver'] === $userId) {
                    if ($taskWorkOrderListItem['status'] === TaskWorkOrderModel::STATUS_UNTREATED) {
                        $receiverOrderTask[$taskWorkOrderListItem['task_id']] = ['status' => $taskWorkOrderListItem['status'], 'receiver_unread' => $taskWorkOrderListItem['receiver_unread'] == "yes"];
                    } elseif (!isset($receiverOrderTask[$taskWorkOrderListItem['task_id']]) ||
                        $receiverOrderTask[$taskWorkOrderListItem['task_id']]['status'] != TaskWorkOrderModel::STATUS_UNTREATED) {
                        $receiverOrderTask[$taskWorkOrderListItem['task_id']] = ['status' => $taskWorkOrderListItem['status']];
                    }
                }
            }
        }

        $userInfo = TaskService::getInstance()->queryTaskSupplierInfo($tenantId, [], [], $departmentIdMap, $executorUserId, array_values($tenantIds));
        $defaultStatusListConfig = OptionsService::getInstance()->getTaskStatusList();
        $statusList = array_column($defaultStatusListConfig, null, 'id');
        $taskDealFunction = function ($taskItem) use (
            $userInfo, $statusList, $version, $versionReviewRequestMap,
            $reviewRequestNodeGroup, $taskWorkOrderStatusMap, $taskMakingWorkOrder, $createdByOrderTask, $receiverOrderTask
        ) {
            $currentTenant = $taskItem['tenant_id'];
            $taskItem['assignee_info'] = $taskItem['executor_info'] = $taskItem['department_info'] = null;
            if ($taskItem['executor_tenant_id'] > 0 && $taskItem['executor_tenant_id'] != $taskItem['tenant_id']) {
                $currentTenant = $taskItem['executor_tenant_id'];
            } else {
                $taskItem['assignee_info'] = $userInfo['executor'][$taskItem['assignee']] ?? null;
                $taskItem['executor_info'] = $userInfo['executor'][$taskItem['executor']] ?? null;
                $taskItem['department_info'] = $userInfo['department'][$taskItem['department_id']] ?? null;
            }
            $taskItem['status'] = $statusList[$taskItem['task_status']] ?? null;
            $taskItem['tenant_info'] = $userInfo['tenant'][$currentTenant] ?? null;
            $taskItem['version'] = $version[$taskItem['id']] ?? null;

            //补充审核进度
            $taskItem['review_progress'] = null;
            if (isset($version[$taskItem['id']]) && isset($versionReviewRequestMap[$version[$taskItem['id']]['id']])
                && isset($reviewRequestNodeGroup[$versionReviewRequestMap[$version[$taskItem['id']]['id']]])) {
                $taskItem['review_progress'] = $reviewRequestNodeGroup[$versionReviewRequestMap[$version[$taskItem['id']]['id']]];
            }
            //补充工单处理状态
            $taskItem['task_work_order_status'] = !in_array($taskItem['id'], $taskMakingWorkOrder);

            //是否能上传任务制作的工单
            $taskItem['is_upload_task_making'] = $taskMakingWorkOrder[$taskItem['id']] ?? true;

            //创建者小红点
            $taskItem['work_order_record_unread'] = in_array($taskItem['id'], $createdByOrderTask);

            //接收者小红点,处理按钮
            $taskItem['deal_task_work'] = false;
            $taskItem['deal_task_work_unread'] = false;
            $taskItem['record_work_order'] = false;
            if (isset($receiverOrderTask[$taskItem['id']])) {
                $taskItem['deal_task_work'] = $receiverOrderTask[$taskItem['id']]['status'] === TaskWorkOrderModel::STATUS_UNTREATED;
                $taskItem['deal_task_work_unread'] = $receiverOrderTask[$taskItem['id']]['receiver_unread'] ?? false;
                $taskItem['record_work_order'] = in_array($receiverOrderTask[$taskItem['id']]['status'], [TaskWorkOrderModel::STATUS_PROCESSED, TaskWorkOrderModel::STATUS_EXPIRED]);
            }
            unset($taskItem['assignee'], $taskItem['executor'], $taskItem['executor_tenant_id'], $taskItem['tenant_id'], $taskItem['department_id'], $taskItem['task_status']);
            return $taskItem;
        };

        $taskDealStepCategoryFunction = $taskDealFunction;
        if ($type === 'step_category') {
            $taskDealFunction = function ($taskItem) use (&$taskDealStepCategoryFunction, &$stepTaskMap) {
                if (!empty($stepTaskMap[$taskItem['entity_id']][$taskItem['step_category_id']])) {
                    $taskItem['task_status'] = $stepTaskMap[$taskItem['entity_id']][$taskItem['step_category_id']]['task_status'];
                    $taskItem['plan_end_time'] = $stepTaskMap[$taskItem['entity_id']][$taskItem['step_category_id']]['plan_end_time'];
                    $taskItem['plan_start_time'] = $stepTaskMap[$taskItem['entity_id']][$taskItem['step_category_id']]['plan_start_time'];
                    $taskItem['end_time'] = $stepTaskMap[$taskItem['entity_id']][$taskItem['step_category_id']]['end_time'];
                }
                return $taskDealStepCategoryFunction($taskItem);
            };
        } elseif ($type === 'step') { //工序需要补充工序分类名称
            //补充工序分类名称
            $stepCategory = [];
            if (!empty($stepCategoryIds)) {
                $stepCategory = model(StepCategoryModel::class)->where(['id' => ['IN', $stepCategoryIds]])->field('id,name')->select();
                $stepCategory = array_column($stepCategory, null, 'id');
            }
            $taskDealFunction = function ($taskItem) use (&$taskDealStepCategoryFunction, &$stepCategory) {
                $taskItem['step_category_name'] = $stepCategory[$taskItem['step_category_id']]['name'];
                return $taskDealStepCategoryFunction($taskItem);
            };
        }

        $task = array_map($taskDealFunction, $task);
        $task = array_group_by($task, 'entity_id');

        //4. 向镜头里填入序列数据
        $shotEntityTaskMap = [];
        foreach ($shotEntityList as $shotEntityItem) {
            $shotTask = [];
            if (array_key_exists($shotEntityItem['entity_id'], $task)) {
                $shotTask = $task[$shotEntityItem['entity_id']];
            }

            if (array_key_exists($shotEntityItem['id'], $task)) {
                $shotTask = array_merge($shotTask, $task[$shotEntityItem['id']]);
            }

            $shotEntityItem['task_children'] = $shotTask;

            if (!array_key_exists($shotEntityItem['entity_id'], $shotEntityTaskMap)) {
                $shotEntityTaskMap[$shotEntityItem['entity_id']] = [$shotEntityItem];
            } else {
                $shotEntityTaskMap[$shotEntityItem['entity_id']][] = $shotEntityItem;
            }
        }


        //4. 向序列里填入镜头数据
        foreach ($sequenceEntityList as &$sequenceEntityItem) {
            $sequenceEntityItem['shot_task'] = [];

            //如果该序列存在镜头,则以镜头任务以及序列的任务补充子项,否则只用序列的任务来补充数据
            if (isset($shotEntityTaskMap[$sequenceEntityItem['id']])) {
                $sequenceEntityItem['shot_task'] = $shotEntityTaskMap[$sequenceEntityItem['id']];
            } elseif (isset($task[$sequenceEntityItem['id']])) {
                $sequenceEntityItem['shot_task'] = [
                    [
                        'id' => 0,
                        'name' => "",
                        'entity_id' => 0,
                        'task_children' => $task[$sequenceEntityItem['id']]
                    ]
                ];
            }
        }

        return $sequenceEntityList;
    }

    /**
     * 获取全生命周期相关数据统计
     * @param $filter
     * @return array
     * @throws \think\Exception
     */
    public function taskAllLifeCycleLinkDataCount($filter)
    {
        $module = $filter['module'];
        $stepType = $filter['step_type'];
        $projectId = $filter['project_id'];
        $result = [];
        switch ($module) {
            case 'asset':
                $designModuleId = module_by_code('design')['id'];
                $levelModuleId = module_by_code('level')['id'];
                $assetModuleId = module_by_code('asset')['id'];
                $assetCount = model(EntityModel::class)->where(['project_id' => $projectId, 'module_id' => $designModuleId])->count();
                $moduleIds = [$designModuleId, $levelModuleId, $assetModuleId];
                $taskCount = model(TaskModel::class)->where(['project_id' => $projectId, 'entity_module_id' => ["IN", $moduleIds], "step_type" => $stepType])->count();
                $result = [
                    'asset_count' => $assetCount,
                    'task_count' => $taskCount
                ];
                break;
            case 'shot':
                $sequenceModuleId = module_by_code('sequence')['id'];
                $shotModuleId = module_by_code('shot')['id'];
                $sequenceCount = model(EntityModel::class)->where(['project_id' => $projectId, 'module_id' => $sequenceModuleId])->count();
                $shotCount = model(EntityModel::class)->where(['project_id' => $projectId, 'module_id' => $shotModuleId])->count();
                $moduleIds = [$sequenceModuleId, $shotModuleId];
                $taskCount = model(TaskModel::class)->where(['project_id' => $projectId, 'entity_module_id' => ["IN", $moduleIds], "step_type" => $stepType])->count();
                $result = [
                    'sequence_count' => $sequenceCount,
                    'shot_count' => $shotCount,
                    'task_count' => $taskCount
                ];
                break;
        }
        return $result;
    }

    /**
     * 当前用户部门的工时统计
     * @param $param
     * @param int $userUnionId
     * @return array
     * @throws Exception
     */
    public function getTeamTaskManHourStatistics($param, int $userUnionId)
    {
        $userInfo = teamones_request('teamones-im', 'user/get_other_user_info', ['user_id' => $userUnionId])['data'];
        $tenant = $userInfo['tenant'] ?? null;
        if (empty($tenant)) {
            return [];
        }
        $departmentId = $tenant['department_id'] ?? 0;
        $tenantId = $tenant['id'] ?? 0;
        if ($departmentId <= 0 || $tenant['id'] <= 0) {
            return [];
        }
        $requestData = ["param" => ["filter" => [
            "tenant_id" => $tenantId,
            "department_id" => $departmentId,
        ]]];
        $userListResult = teamones_request('teamones-im', 'tenant/select_department_user', $requestData);
        $userList = $userListResult['data']['rows'];

        $userUnionIdData = array_column($userList, 'user_id');
        $userService = UserService::getInstance();
        $users = $userService->getUsersByUnionIds($userUnionIdData, 'id,union_id,name,phone', true);
        $users = array_column($users, null, 'id');
        $userIdData = array_column($users, 'id');

        if (empty($userIdData)) {
            return [];
        }

        $filter = $param['param']['filter'] ?? [];
        if (isset($filter['project_id']) && (int)$filter['project_id'] <= 0) {
            unset($filter['project_id']);
        }
        $filter['executor'] = ["IN", implode(',', $userIdData)];
        //工时统计
        $taskModel = model(TaskModel::class);
        $taskManHourList = $taskModel
            ->where($filter)->group("executor")
            ->field("executor,SUM(man_hour) AS total_plan_man_hour,SUM(actual_man_hour) AS total_actual_man_hour")
            ->order("total_plan_man_hour DESC,total_actual_man_hour DESC")
            ->select();

        $res = [];
        $planHour = [
            "title" => "计划工时",
            "value" => [],
        ];
        $actualHour = [
            "title" => "实际工时",
            "value" => [],
        ];

        $res['users'] = array_column($users, null);
        $taskManHourList = array_column($taskManHourList, null, 'executor');
        foreach ($res['users'] as $user) {
            $planHour['value'][] = isset($taskManHourList[$user['id']]) ? (int)$taskManHourList[$user['id']]['total_plan_man_hour'] : 0;
            $actualHour['value'][] = isset($taskManHourList[$user['id']]) ? (int)$taskManHourList[$user['id']]['total_actual_man_hour'] : 0;
        }
        $res['list'] = [$actualHour, $planHour,];
        return $res;
    }

    /**
     * 获取任务统计数据
     * @param $param
     * @param int $userId
     * @param int $unionId
     * @return array
     * @throws \Exception
     */
    public function getTaskStatistics($param, int $userId, int $unionId)
    {
        $userInfo = teamones_request('teamones-im', 'user/get_other_user_info', [
            'user_id' => $unionId,
        ])['data'];
        $roleCodeList = array_column($userInfo['role_info'], 'code');
        $tenant = $userInfo['tenant'] ?? [];
        if (empty($roleCodeList)) {
            throw_strack_exception("you don`t have role info", ErrorCode::ROLE_INFO_NOT_EXIST);
        }
        $roleCodeList = array_unique($roleCodeList);
        $executorIds = [$userId];
        $extraFilter = $param['param']['filter'] ?? [];

        if (isset($extraFilter['project_id']) && (int)$extraFilter['project_id'] <= 0) {
            unset($extraFilter['project_id']);
        }

        foreach ($roleCodeList as $roleCode) {
            switch ($roleCode) {
                case "artist":
                    //艺术家 只统计自己的任务
                    $extraFilter[] = [
                        'task.executor' => [
                            'IN', implode(',', $executorIds)
                        ]
                    ];
                    break;
                case "headman":
                    //组长
                    try {
                        $requestData = ["param" => [
                            'filter' => [
                                'department_id' => $tenant['department_id'],
                            ]
                        ]];
                        $departmentUsers = teamones_request('teamones-im', 'tenant/select_tenant_user', $requestData)['data'];
                    } catch (\Exception $e) {
                        $departmentUsers = [];
                        trace(format_exception_info($e), 'ERR');
                    }

                    $userUnionIdData = array_column($departmentUsers, 'id');

                    $executorIds = array_merge($executorIds, $userUnionIdData);
                    $extraFilter[] = [
                        'task.executor' => [
                            'IN', implode(',', $executorIds)
                        ]
                    ];
                    break;
                case "producer":
                    //制片
                    $projectMemberModel = model(ProjectMemberModel::class);
                    //查看我负责的项目
                    $userId = request()->getUserId();
                    $projectIdData = $projectMemberModel
                        ->where(['user_id' => $userId, 'role_code' => 'producer'])
                        ->field("project_id")
                        ->distinct(true)
                        ->select();
                    $projectIdData = array_column($projectIdData, 'project_id');
                    // 我负责的项目 或者是我创建的项目
                    $projectModel = model(ProjectModel::class);
                    $poo = [
                        'filter' => [
                            ["project.id" => ["IN", implode(',', $projectIdData)]],
                            ["project.created_by" => $userId],
                            "_logic" => "OR"
                        ],
                        'fields' => "project.id"
                    ];
                    $projectList = $projectModel->selectData($poo);
                    $projectIdData = array_column(array_column($projectList['rows'], 'project'), 'id');
                    $extraFilter[] = [
                        'task.project_id' => ['IN', implode(',', $projectIdData)]
                    ];
                    break;
                case "director":
                    //导演
                    $episodesData = EpisodeAllocationService::getInstance()->getEpisodesAllocationEntityIds($userId, []);
                    $directorEntityIds = array_merge($episodesData['episode']['ids'], $episodesData['sequence']['ids'], $episodesData['shot']['ids']);

                    $directorEntityFilter = [
                        'entity_module_id' => ['IN', "{$episodesData['episode']['module_id']},{$episodesData['sequence']['module_id']},{$episodesData['shot']['module_id']}"]
                    ];
                    if (!empty($directorEntityIds)) {
                        $directorEntityFilter['entity_id'] = ['IN', join(',', $directorEntityIds)];
                    } else {
                        $directorEntityFilter['entity_id'] = 0;
                    }
                    $extraFilter[] = $directorEntityFilter;
                    break;
                default:
            }
        }


        // 获取状态id分组通过状态从属关系
        $statusService = StatusService::getInstance();
        $allStatusData = $statusService->getStatusIdGroupByCorrespond();

        // 历史项目不统计, 项目状态为 done 或者 hide
        $projectModel = model(ProjectModel::class);
        $projectExcludeStatusIds = join(',', array_merge($allStatusData['done'], $allStatusData['hide']));
        $excludeProjects = $projectModel->field('id')->where(['_string' => "json_extract(json,'$.project_status') IN ('{$projectExcludeStatusIds}')"])->select();
        $excludeProjectIds = array_column($excludeProjects, 'id');

        /**
         *- 预警任务：
         *- 审核中任务：状态类型为 daily 的任务
         *- 逾期任务：计划结束时间小于当前时间的任务
         *- 进行中任务：状态类型为 in_progress 的任务
         *- 完成任务：状态类型为 done、hide 的任务
         *- 全部任务:
         */

        $taskStatistics = [
            'warning' => 0,
            'daily' => 0,
            'done' => 0,
            'total' => 0,
            'overdue' => 0,
            'in_progress' => 0,
        ];

        $taskModel = model(TaskModel::class);

        //全部
        $tmpWhere = [
            'project_id' => ['NOT IN', join(',', $excludeProjectIds)],
        ];
        $tmpWhere = array_merge($tmpWhere, $extraFilter);
        $taskStatistics['total'] = $taskModel->where($tmpWhere)->count();

        //逾期
        $tmpWhere = [
            'project_id' => ['NOT IN', join(',', $excludeProjectIds)],
            'plan_end_time' => ['LT', time()],
        ];
        $tmpWhere = array_merge($tmpWhere, $extraFilter);
        $taskStatistics['overdue'] = $taskModel->where($tmpWhere)->count();

        //预警任务
        // TODO 预警任务 统计
        $taskStatistics['warning'] = $taskStatistics['overdue'];

        // 审核任务数量
        if (!empty($allStatusData['daily'])) {
            $taskDailyBackStatusIds = join(',', $allStatusData['daily']);
            $tmpWhere = [
                'project_id' => ['NOT IN', join(',', $excludeProjectIds)],
                '_string' => "JSON_UNQUOTE(JSON_EXTRACT(json,'$.task_status')) IN ({$taskDailyBackStatusIds})"
            ];
            $tmpWhere = array_merge($tmpWhere, $extraFilter);

            $taskStatistics['daily'] = $taskModel->where($tmpWhere)->count();
        }

        // 进行中任务
        if (!empty($allStatusData['in_progress'])) {
            $taskDailyBackStatusIds = join(',', $allStatusData['in_progress']);
            $tmpWhere = [
                'project_id' => ['NOT IN', join(',', $excludeProjectIds)],
                '_string' => "JSON_UNQUOTE(JSON_EXTRACT(json,'$.task_status')) IN ({$taskDailyBackStatusIds})"
            ];
            $tmpWhere = array_merge($tmpWhere, $extraFilter);

            $taskStatistics['in_progress'] = $taskModel->where($tmpWhere)->count();
        }

        // 完成任务数量
        if (!empty($allStatusData['done']) || !empty($allStatusData['hide'])) {
            $taskDoneBackStatusIds = join(',', array_merge($allStatusData['done'], $allStatusData['hide']));
            $tmpWhere = [
                'project_id' => ['NOT IN', join(',', $excludeProjectIds)],
                '_string' => "JSON_UNQUOTE(JSON_EXTRACT(json,'$.task_status')) IN ({$taskDoneBackStatusIds})"
            ];
            $tmpWhere = array_merge($tmpWhere, $extraFilter);

            $taskStatistics['done'] = $taskModel->where($tmpWhere)->count();
        }

        return $taskStatistics;
    }

    /**
     * 接收者待处理的工单
     * @param $userId
     * @param $tenantId
     * @param $projectId
     * @param $status
     * @return array
     */
    public function receiverWaitDealWorkOrderTaskFilter($userId, $tenantId, $projectId, $status)
    {
        $taskWorkOrderFilter = ["receiver" => $userId, "tenant_id" => $tenantId, "status" => ["IN", $status]];
        if (!empty($projectId)) {
            $taskWorkOrderFilter["project_id"] = $projectId;
        }

        $taskWorkOrder = model(TaskWorkOrderModel::class)
            ->where($taskWorkOrderFilter)
            ->field("task_id")->select();

        return array_column($taskWorkOrder, 'task_id');
    }

    /**
     * 创建者待处理的工单
     * @param $userId
     * @param $tenantId
     * @param $projectId
     * @param $status
     * @return array
     */
    public function createdByWaitDealWorkOrderTaskFilter($userId, $tenantId, $projectId, $status)
    {
        $taskWorkOrderFilter = ["created_by" => $userId, "tenant_id" => $tenantId, "status" => ["IN", $status]];
        if (!empty($projectId)) {
            $taskWorkOrderFilter["project_id"] = $projectId;
        }

        $taskWorkOrder = model(TaskWorkOrderModel::class)
            ->where($taskWorkOrderFilter)
            ->field("task_id")->select();

        return array_column($taskWorkOrder, 'task_id');
    }

    /**
     * 获取会话的工单未读
     * @param $userId
     * @param $tenantId
     * @param array $taskWorkOrderIds
     * @return array
     */
    public function getTaskWorkChatIsUnread($userId, $tenantId, $taskWorkOrderIds = [])
    {
        $unionId = model(UserModel::class)->where(['id' => $userId])->value("union_id");
        $param = [
            "filter" => [
                'link_type' => 'task_work_order',
                'user_id' => $unionId,
                'from_tenant_id' => $tenantId,
            ]
        ];
        if (!empty($taskWorkOrderIds)) {
            $param['filter']['link_id'] = ["-in", join(",", $taskWorkOrderIds)];
        }
        $requestData = [
            "param" => $param
        ];
        $chat = teamones_request('teamones-im', 'chat/get_chat_is_unread', $requestData);
        $chat = $chat['data'];
        return array_column($chat, 'link_id');
    }
}
